<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta content="HTML Tidy, see www.w3.org" name="generator" />
  <title>Programming for CoffeeMud 5.9</title>
  <link media="screen" type="text/css" href="style.css" rel="StyleSheet" />
<!-- Modified by Josh Mueller, 2006-5-6, fix validation problems, reformat, fix spelling errors -->
</head>
<body>
<center>
<table style="width: 1379px; height: 98129px;" border="1"
 cellpadding="10" cellspacing="0">
  <tbody>
    <tr>
      <td colspan="2" align="left" bgcolor="#dfdfdf" width="100%">
      <h1>Programming
for
CoffeeMud 5.9</h1>
      </td>
    </tr>
    <tr>
      <td align="left" valign="top" width="20%">
      <ul>
        <li><a href="#overview">Overview</a></li>
        <li> <a href="#BUILD">Building</a>
          <ul>
            <li><a href="#buildwin">Windows</a></li>
            <li><a href="#buildunix">Unix</a></li>
            <li><a href="#external">External Components</a></li>
            <li><a href="#IMPORTS">Default Import List</a></li>
          </ul>
        </li>
        <li> <a href="#TEXT">Text</a>
          <ul>
            <li><a href="#nametag">Target Info Tag</a></li>
            <li><a href="#textcolor">Color</a></li>
          </ul>
        </li>
        <li> <a href="#javascript">JavaScripting</a>
          <ul>
            <li><a href="#writingjavascript">Writing Your First
Javascript</a></li>
          </ul>
        </li>
        <li> <a href="#DIG1">Core Topic 1: Message Passing</a>
          <ul>
            <li><a href="#majorcode">Major Code Bitmask</a></li>
            <li><a href="#messagepreview">Message Previewing</a></li>
            <li><a href="#messageflagging">Message Flagging and
Modification</a></li>
            <li><a href="#messageexecution">Message Execution</a></li>
            <li><a href="#messagetrailers">Message Trailers</a></li>
          </ul>
        </li>
        <li> <a href="#DIG2">Core Topic 2: State Layers</a>
          <ul>
            <li><a href="#phystats">PhyStats fields</a></li>
            <li><a href="#charstats">CharStats codes</a></li>
            <li><a href="#charstate">CharState</a></li>
          </ul>
        </li>
        <li><a href="#DIG3">Core Topic 3: Threading</a></li>
        <li> <a href="#DIG4">Core Topic 4: Core Libraries</a>
          <ul>
            <li><a href="#corepurpose">Core class purposes</a></li>
            <li><a href="#corelibrarymap">Library mappings</a></li>
            <li><a href="#corecommon">Common Classes</a></li>
          </ul>
        </li>
        <li><a href="Programming.html#DIG5">Core Topic 5: Input</a></li>
        <li><a href="Programming.html#DIG6">Core Topic 6: Database
Tables</a></li>
        <li><a href="#CMDS">Commands</a></li>
        <li> <a href="#MOBS">MOBs</a>
          <ul>
            <li><a href="#mobcoding">Coding a new MOB</a></li>
            <li><a href="#moblife">Life and Death</a></li>
          </ul>
        </li>
        <li> <a href="#ITEMS">Items</a>
          <ul>
            <li><a href="#itemlife">Creation and Destruction</a></li>
          </ul>
        </li>
        <li><a href="#BEHAVS">Behaviors</a></li>
        <li><a href="#CLASSES">Character Classes</a></li>
        <li><a href="#RACES">Races</a></li>
        <li><a href="#EXITS">Exits</a></li>
        <li><a href="#LOCALES">Locales</a></li>
        <li><a href="#AREAS">Areas</a></li>
        <li><a href="#PROPS">Properties</a></li>
        <li> <a href="#SKILLS">Skills</a>
          <ul>
            <li><a href="#skillquality">Skill Nature Flags</a></li>
            <li><a href="#skillflags">Skill Affect Flags</a></li>
          </ul>
        </li>
        <li> <a href="#SPC">Spells, Prayers, and Chants</a>
          <ul>
            <li><a href="#spells">Spells</a></li>
            <li><a href="#spelldomain">Spell Domains</a></li>
            <li><a href="#prayers">Prayers</a></li>
            <li><a href="#chants">Chants</a></li>
          </ul>
        </li>
        <li><a href="#SONGS">Songs</a></li>
        <li> <a href="#COMMON">Common Skills</a>
          <ul>
            <li><a href="#skillgathering">Gathering Skill</a></li>
            <li><a href="#skillcrafting">Crafting Skill</a></li>
          </ul>
        </li>
        <li><a href="#POISON">Poisons</a></li>
        <li><a href="#DISEASE">Diseases</a></li>
        <li><a href="#TRAPS">Traps &amp; Bombs</a></li>
        <li><a href="#LANGS">Languages</a></li>
      </ul>
      </td>
      <td align="left" valign="top"> <img src="images/mug.jpg"
 alt="CoffeeMud logo" />
      <h2><a name="overview" id="overview">Overview</a></h2>
      <p>The purpose of this
document is to assist those who wish to
add custom Items, MOBs, Behaviors, Properties, or other objects to
CoffeeMud. The reader should be familiar with Java programming, and
should be experienced with writing and compiling Java classes. The
object oriented notions of class inheritance and polymorphism, as well
as the Java constructs of interfaces should be at least vaguely
familiar to you before attempting to build classes for CoffeeMud. Also,
it is expected that all of the ideas presented in the <a
 href="ArchonGuide.html">Archons Guide</a>
and <a href="GameBuildersGuide.html">Game
Builders Guide</a>
are completely familiar. The difference between a GenItem and a
StdItem, or a GenMob and a GenPostman will not be explained in this
document.</p>
      <p>It is not expected that
someone would wish to dive in and make
wholesale changes to the CoffeeMud system right away, but is more
likely wanting to fill in a functional gap in the system for their own
needs. For this reason, this document is not organized as a
comprehensive guide to programming CoffeeMud. Instead, it is designed
to be a quick reference for those who wish to create the spot MOB,
Behavior, Item, or Property for use on their maps.</p>
      <p>With this in mind then,
let's start out with some brief
development instructions, and then and in no particular order, discuss
the several essential object types in CoffeeMud are presented.</p>
      <img src="images/sprockets.jpg" alt="Recompiling" />
      <h2><a name="BUILD" id="BUILD">Rebuilding CoffeeMud</a></h2>
      <h3><a name="buildwin" id="buildwin">In Microsoft
Windows</a></h3>
      <ul>
        <li>
          <p>Go to your coffeemud
directory and edit the make.bat, the
first line will be something like: <code>SET
JAVACPATH=
C:\Program Files\Java\jdk1.6.0_22\bin\javac</code>
This might be
different for you
depending on what version of the Java JDK you installed, and where your
java development package is installed.</p>
        </li>
        <li>
          <p>Save the bat file.</p>
        </li>
        <li>
          <p>Run the bat file by
double clicking on it. This will
compile the mud, making all the .class files.</p>
        </li>
      </ul>
      <h3><a name="buildunix" id="buildunix">In Unix</a></h3>
      <ul>
        <li>
          <p>Go to your coffeemud
directory and edit the makeUNIX.sh,
the first line will be something like: <code>Java_Home=/home/knoppix/jdk1.6.0_22</code>
This might be different for you depending on what version of the Java
JDK you installed, and where your java
development package is installed.</p>
        </li>
        <li>
          <p>Save the shell script.</p>
        </li>
        <li>
          <p>Issue this command: <code>chmod
755 makeUNIX.sh</code></p>
        </li>
        <li>
          <p>Execute the shell
script. This will compile the mud,
making all the .class files.</p>
        </li>
      </ul>
      <h3><a name="external" id="external">Introducing
External
Components</a></h3>
      <p>If you perused the
coffeemud.ini file as mentioned in the
Installation Guide, you may have noticed and wondered about the section
near the bottom which lists the default load paths for the several
CoffeeMud
objects.</p>
      <p>By default, the CoffeeMud
engine dynamically loads the vast
majority of its object code at boot time by referring to the paths
specified in the coffeemud.ini file. The value <code>%DEFAULT%</code>
is always used as a substitute for the default CoffeeMud object path.
For instance, if you installed CoffeeMud at "<code>C:\CoffeeMud\</code>",
then "<code>BEHAVIORS=%DEFAULT%</code>"
in the ini file would load "<code>C:\CoffeeMud\com\planet_ink\coffee_mud\Behaviors\*.class</code>"
into its behavior set.</p>
      <p>This default object boot
paths may be removed or added-to
using semicolon delimited paths, or even replaced with your own object
boot directories. In fact, when adding objects to your CoffeeMud boot
sequence, it is recommended that you place your objects in a separate
directory path inside your CoffeeMud folder and add its path to the
coffeemud.ini file under the proper setting. The order in which you
place multiple paths in a single entry is also significant, as the
CoffeeMud ClassLoader will load the files in the order in which they
appear listed. For instance:</p>
      <pre>MOBS=%DEFAULT%;/resources/examples/MyClass.class;/resources/otherclasses<br /></pre>
      <p>Will cause the default
CoffeeMud versions of the mob classes
to be loaded first, followed by MyClass.class, followed by all the
class files in the resources/otherclasses folder in your CoffeeMud
package. Also notice that the ClassLoader follows the rules of the CMFS
described in the Archons Guide, meaning that the forward slash is
always the proper path separator, and that no folder outside of your
CoffeeMud package may be referenced. Also bear in mind that case is
sensitive when naming Java class files, even in these boot paths.</p>
      <p>When writing these custom
classes for your special object boot
directory(s), it is important to keep a number of things in mind:</p>
      <ul>
        <li>
          <p>Do not mix your
object types in the same directory! Never
try to boot custom items from the same directory from which you boot
your custom mobs. It will only confuse you and CoffeeMud.</p>
        </li>
        <li>
          <p>Java Packaging is
irrelevant, you may package your classes
or not.</p>
        </li>
        <li>
          <p>Implement or extend a
class that implements the proper
interfaces. If you are coding mobs, this would mean the MOB interface.
If you are coding locales, the Room interface, etc, etc. See the
section on the object type you are coding for the proper interface to
implement. You may get around this requirement by extending one of the
base classes, such as StdItem, StdMOB, StdContainer, StdRoom,
StdAbility, GenMob, GenItem, GenContainer, etc.</p>
        </li>
        <li>
          <p>Make sure the <code>ID()</code>
method in your classes
always matches the name of your class. You will understand this better
as you reference the object sections below.</p>
        </li>
        <li>
          <p>Try to make the <code>name()</code>
methods in your
classes return name values unique among all objects, especially objects
of that type. This is not a hard fast rule, and breaking it will not
cause malfunction in the system, but breaking this rule WILL make
writing help files impossible.</p>
        </li>
        <li>
          <p>Class files loaded
directly in the CoffeeMud classpath can
not be reloaded at run-time using the <code>UNLOAD</code>
and <code>LOAD</code>
commands. If you plan on making changes to your classes during
run-time, place them in their own directories.</p>
        </li>
        <li>
          <p>As a general rule,
you may import any "<code>interfaces.*</code>"
packages in the base CoffeeMud structure, any core Java packages, the
CoffeeMud "<code>core.*</code>"
package, and any single base CoffeeMud class you may be extending. Do
not import more than that. Use the CMClass getter methods if you need
to create new instances of CoffeeMud classes, and use the CMLib methods
to access her code libraries.</p>
        </li>
      </ul>
      <h3><a name="IMPORTS" id="IMPORTS">Complete Default
Import List</a></h3>
      <pre>import com.planet_ink.coffee_mud.core.*;<br />import com.planet_ink.coffee_mud.core.collections.*;<br />import com.planet_ink.coffee_mud.core.interfaces.*;<br />import com.planet_ink.coffee_mud.Abilities.interfaces.*;<br />import com.planet_ink.coffee_mud.Areas.interfaces.*;<br />import com.planet_ink.coffee_mud.Behaviors.interfaces.*;<br />import com.planet_ink.coffee_mud.CharClasses.interfaces.*;<br />import com.planet_ink.coffee_mud.Commands.interfaces.*;<br />import com.planet_ink.coffee_mud.Common.interfaces.*;<br />import com.planet_ink.coffee_mud.Exits.interfaces.*;<br />import com.planet_ink.coffee_mud.Items.interfaces.*;<br />import com.planet_ink.coffee_mud.Locales.interfaces.*;<br />import com.planet_ink.coffee_mud.MOBS.interfaces.*;<br />import com.planet_ink.coffee_mud.Races.interfaces.*;<br />import com.planet_ink.coffee_mud.Libraries.interfaces.*;<br />import java.io.IOException;<br />import java.util.*;<br /></pre>
      <img src="images/rainbow.jpg" alt="Text" />
      <h2><a name="TEXT" id="TEXT">Text</a></h2>
      <p>Before we get started
with objects, needs must the topic of
text display be covered. Throughout the system you will see text being
sent to the user. Since a mud is a text producing engine, this should
be no great surprise. However, within that text you will often see
different kinds of codes and tags which affect the output. For
instance, consider the following lines:</p>
      <pre>msg=CMClass.newMsg(mob,target,this,CMMsg.MSG_OK_ACTION,"&lt;S-NAME&gt; reach(es) for &lt;T-NAMESELF&gt;.");<br />mob.location().show(mob,null,CMMsg.MSG_OK_ACTION,"&lt;S-NAME&gt; regain(s) &lt;S-HIS-HER&gt; feet.");<br /><br /></pre>
      <p>Focusing only on the text
for a moment, you will notice that
special tags are used to designate a player name, or the name of the
target of a spell. You will also notice that (s) and (es) is used to
modify the proper form of a verb. These are key features of the
CoffeeMud text engine. Here is a more complete list of available tags:</p>
      <a name="nametag" id="nametag"> </a>
      <table bgcolor="#ffffcc" border="1">
        <tbody>
          <tr>
            <td><code>&lt;S-HIS-HER&gt;</code> </td>
            <td>Outputs 'Your' if
Observer=Source, otherwise
'His'/'Her'.</td>
          </tr>
          <tr>
            <td><code>&lt;S-HIM-HER&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Source, otherwise 'Him'/'Her'.</td>
          </tr>
          <tr>
            <td><code>&lt;S-NAME&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Source, otherwise the Name.</td>
          </tr>
          <tr>
            <td><code>&lt;S-NAMESELF&gt;</code> </td>
            <td>Outputs 'Yourself'
if Observer=Source, otherwise the
Name</td>
          </tr>
          <tr>
            <td><code>&lt;S-NAMENOART&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Source, otherwise the Name
minus any prefix articles (a, an, some, etc..).</td>
          </tr>
          <tr>
            <td><code>&lt;S-HE-SHE&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Source, otherwise 'He'/'She'</td>
          </tr>
          <tr>
            <td><code>&lt;S-SIRMADAM&gt;</code> </td>
            <td>Outputs
'Sir'/'Madam'</td>
          </tr>
          <tr>
            <td><code>&lt;S-IS-ARE&gt;</code> </td>
            <td>Outputs 'Are' if
Observer=Source, otherwise 'Is'.</td>
          </tr>
          <tr>
            <td><code>&lt;S-HAS-HAVE&gt;</code> </td>
            <td>Outputs 'Have' if
Observer=Source, otherwise 'Has'.</td>
          </tr>
          <tr>
            <td><code>&lt;S-YOUPOSS&gt;</code> </td>
            <td>Outputs 'Your' if
Observer=Source, otherwise the Name`s</td>
          </tr>
          <tr>
            <td><code>&lt;S-HIM-HERSELF&gt;</code> </td>
            <td>Outputs 'Yourself'
if Observer=Source, otherwise the
'Himself'/'Herself'</td>
          </tr>
          <tr>
            <td><code>&lt;S-HIS-HERSELF&gt;</code> </td>
            <td>Outputs 'Yourself'
if Observer=Source, otherwise the
'Hisself'/'Herself'</td>
          </tr>
          <tr>
            <td><code>&lt;T-HIS-HER&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Target, otherwise 'His'/'Her'.</td>
          </tr>
          <tr>
            <td><code>&lt;T-HIM-HER&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Target, otherwise 'Him'/'Her'.</td>
          </tr>
          <tr>
            <td><code>&lt;T-NAME&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Target, otherwise the Name.</td>
          </tr>
          <tr>
            <td><code>&lt;T-NAMESELF&gt;</code> </td>
            <td>Outputs 'Yourself'
if Observer=Target, otherwise the
Name</td>
          </tr>
          <tr>
            <td><code>&lt;T-NAMENOART&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Target, otherwise the Name
minus any prefix articles (a, an, some, etc..).</td>
          </tr>
          <tr>
            <td><code>&lt;T-HE-SHE&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Target, otherwise 'He'/'She'</td>
          </tr>
          <tr>
            <td><code>&lt;T-SIRMADAM&gt;</code> </td>
            <td>Outputs
'Sir'/'Madam'</td>
          </tr>
          <tr>
            <td><code>&lt;T-IS-ARE&gt;</code> </td>
            <td>Outputs 'Are' if
Observer=Target, otherwise 'Is'.</td>
          </tr>
          <tr>
            <td><code>&lt;T-HAS-HAVE&gt;</code> </td>
            <td>Outputs 'Have' if
Observer=Target, otherwise 'Has'.</td>
          </tr>
          <tr>
            <td><code>&lt;T-YOUPOSS&gt;</code> </td>
            <td>Outputs 'Your' if
Observer=Target, otherwise the Name
with an '`s'</td>
          </tr>
          <tr>
            <td><code>&lt;T-HIM-HERSELF&gt;</code> </td>
            <td>Outputs 'Yourself'
if Observer=Source, otherwise the
'Himself'/'Herself'</td>
          </tr>
          <tr>
            <td><code>&lt;T-HIS-HERSELF&gt;</code> </td>
            <td>Outputs 'Yourself'
if Observer=Source, otherwise the
'Hisself'/'Herself'</td>
          </tr>
          <tr>
            <td><code>&lt;S-ACCOUNTNAME&gt;</code> </td>
            <td>Outputs 'You' if
Observer=Source, otherwise the Account
Name.</td>
          </tr>
        </tbody>
      </table>
      <p>Occasionally, you will
find color/font codes embedded in
system strings. For instance:</p>
      <pre>msg.append("^!You are thirsty.^?\n\r");<br /></pre>
      <p>These codes are as
follows:</p>
      <a name="textcolor" id="textcolor"> </a>
      <table bgcolor="#ccffff" border="1">
        <tbody>
          <tr>
            <td><code>^N</code> </td>
            <td>Normal</td>
          </tr>
          <tr>
            <td><code>^!</code> </td>
            <td>Bold</td>
          </tr>
          <tr>
            <td><code>^H</code> </td>
            <td>Highlight</td>
          </tr>
          <tr>
            <td><code>^_</code> </td>
            <td>Underline</td>
          </tr>
          <tr>
            <td><code>^*</code> </td>
            <td>Blink</td>
          </tr>
          <tr>
            <td><code>^/</code> </td>
            <td>Italics</td>
          </tr>
          <tr>
            <td><code>^.</code> </td>
            <td>Reset (turns off
reverse)</td>
          </tr>
          <tr>
            <td><code>^^</code> </td>
            <td>Generates an
untranslated "^" character</td>
          </tr>
          <tr>
            <td><code>^?</code> </td>
            <td>Restores previous
color</td>
          </tr>
          <tr>
            <td><code>^f</code> </td>
            <td>You-Fight</td>
          </tr>
          <tr>
            <td><code>^e</code> </td>
            <td>Fight-You</td>
          </tr>
          <tr>
            <td><code>^F</code> </td>
            <td>Fight</td>
          </tr>
          <tr>
            <td><code>^S</code> </td>
            <td>Spell</td>
          </tr>
          <tr>
            <td><code>^E</code> </td>
            <td>Emote</td>
          </tr>
          <tr>
            <td><code>^T</code> </td>
            <td>Talk</td>
          </tr>
          <tr>
            <td><code>^Q</code> </td>
            <td>Channel Background</td>
          </tr>
          <tr>
            <td><code>^q</code> </td>
            <td>Channel Foreground</td>
          </tr>
          <tr>
            <td><code>^x</code> </td>
            <td>Important message 1</td>
          </tr>
          <tr>
            <td><code>^X</code> </td>
            <td>Important message 2</td>
          </tr>
          <tr>
            <td><code>^Z</code> </td>
            <td>Important message 3</td>
          </tr>
          <tr>
            <td><code>^O</code> </td>
            <td>Room Title</td>
          </tr>
          <tr>
            <td><code>^L</code> </td>
            <td>Room Description</td>
          </tr>
          <tr>
            <td><code>^J</code> </td>
            <td>Weather</td>
          </tr>
          <tr>
            <td><code>^D</code> </td>
            <td>Direction</td>
          </tr>
          <tr>
            <td><code>^d</code> </td>
            <td>Door</td>
          </tr>
          <tr>
            <td><code>^I</code> </td>
            <td>Item</td>
          </tr>
          <tr>
            <td><code>^M</code> </td>
            <td>MOB</td>
          </tr>
          <tr>
            <td><code>^U</code> </td>
            <td>Unexplored
Direction</td>
          </tr>
          <tr>
            <td><code>^u</code> </td>
            <td>Unexplored Door</td>
          </tr>
          <tr>
            <td><code>^w</code> </td>
            <td>White</td>
          </tr>
          <tr>
            <td><code>^g</code> </td>
            <td>Green</td>
          </tr>
          <tr>
            <td><code>^b</code> </td>
            <td>Blue</td>
          </tr>
          <tr>
            <td><code>^r</code> </td>
            <td>Red</td>
          </tr>
          <tr>
            <td><code>^y</code> </td>
            <td>Yellow</td>
          </tr>
          <tr>
            <td><code>^c</code> </td>
            <td>Cyan</td>
          </tr>
          <tr>
            <td><code>^p</code> </td>
            <td>Purple</td>
          </tr>
          <tr>
            <td><code>^W</code> </td>
            <td>Dark White</td>
          </tr>
          <tr>
            <td><code>^G</code> </td>
            <td>Dark Green</td>
          </tr>
          <tr>
            <td><code>^B</code> </td>
            <td>Dark Blue</td>
          </tr>
          <tr>
            <td><code>^R</code> </td>
            <td>Dark Red</td>
          </tr>
          <tr>
            <td><code>^Y</code> </td>
            <td>Dark Yellow</td>
          </tr>
          <tr>
            <td><code>^C</code> </td>
            <td>Dark Cyan</td>
          </tr>
          <tr>
            <td><code>^P</code> </td>
            <td>Dark Purple</td>
          </tr>
          <tr>
            <td><code>^~w</code> </td>
            <td>White Background</td>
          </tr>
          <tr>
            <td><code>^~g</code> </td>
            <td>Green Background</td>
          </tr>
          <tr>
            <td><code>^~b</code> </td>
            <td>Blue Background</td>
          </tr>
          <tr>
            <td><code>^~r</code> </td>
            <td>Red Background</td>
          </tr>
          <tr>
            <td><code>^~y</code> </td>
            <td>Yellow Background</td>
          </tr>
          <tr>
            <td><code>^~c</code> </td>
            <td>Cyan Background</td>
          </tr>
          <tr>
            <td><code>^~p</code> </td>
            <td>Purple Background</td>
          </tr>
          <tr>
            <td><code>^#xxx</code> </td>
            <td>256 color
foreground x=0-5</td>
          </tr>
          <tr>
            <td><code>^##xx</code> </td>
            <td>256 color
foreground xx=hex 00-ff</td>
          </tr>
          <tr>
            <td><code>^|xxx</code> </td>
            <td>256 color
background x=0-5</td>
          </tr>
          <tr>
            <td><code>^||xx</code> </td>
            <td>256 color
background xx=hex 00-ff</td>
          </tr>
          <tr>
            <td><code>^&lt;</code> </td>
            <td>&lt;
character. Used for MXP tags only.</td>
          </tr>
          <tr>
            <td><code>^&gt;</code> </td>
            <td>&gt;
character. Used for MXP tags only.</td>
          </tr>
          <tr>
            <td><code>^&amp;</code> </td>
            <td>&amp;
character. Used for MXP tags only.</td>
          </tr>
        </tbody>
      </table>
      <p>As you might have
guessed, it is preferred that the system
colors (the last codes) be used sparingly, in favor of the more
customizable codes above. Also, be sure to always put foreground color
codes before background color codes. Foreground color codes always
"reset" the
default background color.</p>
      <img src="images/mozilla.jpg" alt="Mozilla Javascript" />
      <h2><a name="javascript" id="javascript">JavaScripting:</a></h2>
      <p>JavaScript is an
interpreted scripting language which is used
in various parts of CoffeeMud. The CoffeeMud engine integrates the
Rhino Javascript interpretor package from Mozilla in such places as the
Scriptable behavior, the JRun command, the ClassLoader, the Quest
engine, and the web server.</p>
      <p>In lieu of a complete
write up on the syntax of this language,
it is suggested that you read the documentation available from the
authors of the interpretor here: <a href="http://www.mozilla.org/js/">http://www.mozilla.org/js/</a>
and <a href="http://www.mozilla.org/rhino/">http://www.mozilla.org/rhino/</a>.</p>
      <p>If you are familiar with
writing Javascript for web browsers,
there are several differences you will need to adjust to when using
Javascript in CoffeeMud. A minor difference is that the Rhino
interpretor requires that all variables be declared before use. A more
important difference is that Javascript Strings are not the same as
Java String objects, and that confusing them can lead to errors. To get
around this problem, all of the implementations of Javascript in
CoffeeMud, with the exception of the ClassLoader,&nbsp;provide a
special
method to convert Javascript strings into Java Strings before passing
them to Java methods or objects which will require them. An example is
below:</p>
      <pre>var javascriptstring=' this is a javascript string ';<br />var javastring=toJavaString(javascriptstring);<br />// and now javastring is a real-live Java-compliant and Java-friendly string<br /></pre>
      <p>When writing Java <span style="font-weight: bold;">classes</span>
in JavaScript, however, this method is only available through the CMLib
object in the core package. This is how you would access the <code>toJavaString()</code>
method from a <span style="font-weight: bold;">class</span>
written in
JavaScript:</p>
      <pre>var javascriptstring=' this is a javascript string ';<br />var javastring=Packages.com.planet_ink.coffee_mud.core.CMLib.toJavaString(javascriptstring);<br />// and now javastring is a real-live Java-compliant and Java-friendly string<br /></pre>
      <p>The most important
difference between coding Javascript for
CoffeeMud and for browsers is that there is no HTML DOM (Document
Object Model), and therefore several of the libraries you are used to
are probably missing, such as Math. For this reason, it is necessary
for you to learn the CoffeeMud object packages in order to get access
to useful data and useful libraries. And now you understand why the
JavaScripting notes are kept in the Programming guide. :)</p>
      <p>To access the CoffeeMud
object packages, you will need to make
use of the Packages object to reference external packages. So long as
the imported objects are in your CoffeeMud classpath, they can be
accessed and used. For instance, to use the CoffeeMud <code>pow(x,y)</code>
function in CMath.java:</p>
      <pre>var lib=Packages.com.planet_ink.coffee_mud.core.CMLib;<br />// the above creates a reference to the CoffeeMud Library as a shortcut<br />var value=lib.math().pow(4,2);<br />// now we can access the math() library from our shortcut.<br /></pre>
      <p>Depending upon the
context from which your script runs (the
Scriptable behavior, JRun command, the Quest engine, or the http/web
server), certain other objects are made available to assist scripts in
properly interacting with their environment. When writing Java classes
in JavaScript for the ClassLoader, however, you must always use the <code>Packages.com.planet_ink.coffee_mud.core.CMLib</code>
reference to access special methods such as the toJavaString method
discussed above.</p>
      <p>In the Scriptable
behavior, several methods are made available
to access objects which are related to the event which triggered the
scripted code. These methods include <code>MOB
source(), Environmental
target(), Environmental host(), Item item1(), Item item2(), String
message(),</code> and <code>MOB
monster()</code>. The JRun command
provides the methods <code>MOB
mob(), int numParms(), String
getParm(int i),</code> and <code>String
getParms()</code>. The web
server makes the <code>HTTPRequest
request()</code> object
available, as well as the method <code>void
write(String s)</code>.
The quest engine makes the current running Quest object available from
the method <code>Quest quest()</code>
and the current state of the
quest setup script available in a custom QuestState object referencing
method called <code>QuestState
setupState()</code></p>
      <p>The last piece of general
information about JavaScript in
CoffeeMud concerns writing Java classes for the CoffeeMud ClassLoader.
Any JavaScript file *.js included in the ClassLoader boot paths (see
the previous section) will be loaded and treated just like any Java
compiled *.class file. The JavaScript file would be parsed, compiled,
and loaded at boot time. For the most part, writing Java Classes in
JavaScript is extremely similar to writing Java Classes in Java. Base
classes may be extended (using the special CoffeeMud <code>//extends</code>
command in your JavaScript), interfaces may be implemented (using the
special CoffeeMud <code>//implements</code>
command in your
JavaScript), super class variables and methods may be accessed (using
the <code>this.variableName</code>
and <code>this.super$methodname()</code>
syntax), and super class methods may be overridden by JavaScript
functions of the same name and number of parameters. Class files
written in Javascript *.js files may also be loaded and unloaded at
runtime using the LOAD and UNLOAD Archon commands, which gives them a
step up on native Java classes in the JVM classpath.</p>
      <h3><a name="writingjavascript" id="writingjavascript">Writing
your first JavaScript</a></h3>
      <p>Below is an example of a
Java Class written in JavaScript.
Examples of Embedded JavaScript in CoffeeMud Virtual Pages (cmvp) web
files can be found in the Web Server Guide. Examples of Embedded
JavaScript in a Scriptable MOBPROG script can be found in the Scripting
Guide.</p>
      <p>Our Java Class example is
called GenLemming.js. It is a sample
MOB class to demonstrate extending the GenMob class to create a type of
modifiable mob for your maps. In this example, we add functionality to
make all mobs in the world created from the GenLemming base suicidal.
To use this class, save the code somewhere in our CoffeeMud folder
under the name "GenLemming.js", and add an object path reference to it
in the MOBS entry in your coffeemud.ini file, as described in section
one.</p>
      <pre>//extends com.planet_ink.coffee_mud.MOBS.GenMob<br /><br />function ID(){return "GenLemming";}<br /><br />var lib=Packages.com.planet_ink.coffee_mud.core.CMLib;<br /></pre>
      <p>The first lines of our
class include the special //extends
command which informs the CoffeeMud ClassLoader that this JavaScript
class will extend GenMob, thereby inhereting all functionality of the
maleable GenMob.</p>
      <p>The <code>ID()</code>
method is required in all CoffeeMud
classes. It must be the simple name of the class, and must match the
name of the JavaScript file containing it. For example, GenLemming.js
contains class GenLemming and returns an ID of "GenLemming". They all
match exactly.</p>
      <p>Lastly, we define the
variable "lib" to act as a shortcut to
the CoffeeMud core Libraries.</p>
      <p>Now, moving on; since we
don't have the ability to write
constructors in JavaScript, any initial fields we need to set whenever
a new instance of our class is created must be done in the CoffeeMud <code>newInstance()</code>
method as shown here:</p>
      <pre>function newInstance()<br />{<br /> var lemm=this.super$newInstance();<br /> lemm.setName("a generic lemming");<br /> lemm.setDisplayText("a generic lemming is waiting to commit suicide");<br /> return lemm;<br />}<br /></pre>
      <p>There are several
interesting points to make here. One is to
notice that the function has no explicit return type, which is part of
the JavaScript standard of being "weakly typed". Also notice the syntax
for calling the SuperClass version of the <code>newInstance()</code>
method -- <code>this.super$newInstance()</code>.
This is very
different from Java syntax and should be noted.</p>
      <p>And now we move on to
overriding our first GenMob method, tick.</p>
      <pre>var countdown = 10;<br /><br />function tick( host, tickID )<br />{<br /> if( !this.amDead() )<br /> {<br /> countdown--;<br /> if( countdown &lt;= 0 )<br /> {<br /> lib.combat().postDeath( null, this, null );<br /> countdown = 10;<br /> }<br /> }<br /> return this.super$tick( host, tickID );<br />}<br /> <br /></pre>
      <p>The <code>public
boolean tick(Tickable host, int tickID)</code>
method from the standard MOB interface is designed to be called every
CoffeeMud tick (about 4 seconds). Now, the tick method in StdMOB, which
is extended by GenMob, handles things like recovering hit points,
automatic combat rounds, and other important periodic activities. It is
explained further in Core Topic 3.</p>
      <p>For our GenLemming, we
create a variable to count down the
ticks from 10 to 0. When the countdown variable reaches 0, we call the <code>postDeath(MOB
killer, MOB killed, CMMsg msg)</code>
method, which is part of the CombatLibrary in the core libraries. "lib"
is the variable we defined above as a shortcut to our core libraries.
The last thing we do is return control to the SuperClass version of the
tick method.</p>
      <p>Now we'll get creative
and implement a message previewer (see
the Core Topic 1 below for more information on message previewing and
handling). This method will be called when any event happens in the
same room as the GenLemming mob. We will use this fact to look for,
capture, and modify the message string which will inform the room of
our impending death. Since it is the previewing method, it will be
called BEFORE the activity actually takes place, giving us a chance to
make our modifications before anyone actually sees the message strings.</p>
      <pre>function okMessage(host,msg)<br />{<br /> if( ( msg.isSource( this ) )<br /> &amp;&amp;( msg.isOthers( "DEATH" ) )<br /> &amp;&amp;( msg.othersMessage() != null )<br /> )<br /> {<br /> msg.setOthersMessage("&lt;S-NAME&gt; jumps off a cliff!!!");<br /> }<br /><br /> return this.super$okMessage(host,msg);<br />}<br /></pre>
      <p>In our message previewing
method, we will check every message
that comes our way, acting only if this particular GenLemming is the
source of the message, that he appears to be dying to others in the
room <code>( isOthers( "DEATH" ) )</code>
and that the message being given to others in the room is a non-null
string. In these conditions, we modify the message which others in the
room see. When our condition is not met, we return control to the
SuperClass-GenMob version of okMessage.</p>
      <img src="images/kiss.jpg" alt="Getting the Message" />
      <h2><a name="DIG1" id="DIG1">Core Topic 1: Getting
the Message:</a></h2>
      <p>CoffeeMud is essentially
a distributed message passing and
handling system, where the actions and events that occur in the system
are represented as messages (Common.interfaces.CMMsg) which are then
previewed, modified, cancelled, and/or reacted to by handlers.
Understanding this idea is key to fully understanding how CoffeeMud
really works, so let's take a second and peruse this concept in more
detail.</p>
      <p>Messages in CoffeeMud, at
least as we are talking about them
here, always represent Events. Events such as a mob picking up an item,
swinging a sword at an opponent, taking damage from a fireball, or
getting pricked by a poisonous needle. These events can never actually
occur in CoffeeMud unless a proper message is generated for them first.
These messages, in the code, implement the interface <code>Common.interfaces.CMMsg</code>,
and are typically an instance of the class <code>Common.DefaultMessage</code>.</p>
      <p>Messages are created at
the moment that the event needs to
occur. This moment can be triggered by the player entering a command
into their telnet client and pressing Enter. It can also by triggered
by the mindless algorithms which animate the mobs. Either way, when the
moment has come, a message is created, and it looks like this:</p>
      <pre>CMMsg msg = CMClass.getMsg(mob, targetMOB, this,<br /> CMMsg.MSG_CAST_ATTACK_VERBAL_SPELL,"^S&lt;S-NAME&gt; invoke a spell at &lt;T-NAME&gt;s feet..^?",<br /> CMMsg.MSG_CAST_ATTACK_VERBAL_SPELL,"^S&lt;S-NAME&gt; invoke(s) a spell at your feet.^?",<br /> CMMsg.MSG_CAST_ATTACK_VERBAL_SPELL,"^S&lt;S-NAME&gt; invokes a spell at &lt;T-NAME&gt;s feet.^?"<br /> );<br /><br /></pre>
      <p>The above message was
taken from the code for the Grease
spell, which calls the <code>core.CMClass.getMsg</code>
method to construct a CMMsg object. Constructing the CMMsg object does
not actually make anything happen, but it is the vital first step. The
message we constructed here, in this case, utilizes every major
component of a message. These components are, in order:</p>
      <ul>
        <li> Source
          <p>The source of any
message must always be a valid reference
to an instance of the MOB interface. In short, all events that occur in
the system are a direct result of the activity of a MOB. This is on the
theory that the universe is controlled and governed by sentience. In
the extremely rare instances where a mob is not readily available to
provide a message source, one should be instantiated -- even if it is
just a blank, new StdMOB.</p>
        </li>
        <li> Target
          <p>The target of a
message may be null, or any valid
reference to an instance of the Environmental interface, which includes
Items, MOBs, Rooms, Exits, etc. The type and context of message you
wish to generate will typically tell you intuitively whether the source
is doing something to someone or something else, or is acting
independently. This is usually another mob or an item, but you will
find examples of all kinds of targets in the code.</p>
        </li>
        <li> Tool
          <p>The tool of a message
may be null, or any valid reference
to an instance of the Environmental interface, which includes Items,
Abilities, MOBs, Rooms, Exits, etc. The tool represents something which
the source is utilizing to accomplish the task or generate the event.
This is typically either an Ability object (like a Spell or Skill being
used), or an Item object (like a weapon in an attack event).</p>
        </li>
        <li> Source Code
          <p>This is an encoded
integer which represents what the
source MOB is actually doing. We'll break down this code below.</p>
        </li>
        <li> Source Message
          <p>This is the string
which the source MOB will see should
the event occur successfully.</p>
        </li>
        <li> Target Code
          <p>This is an encoded
integer which represents what is
happening to the target. If there is no target, this number will
typically have the value of 0 (CMMsg.NOEFFECT).</p>
        </li>
        <li> Target Message
          <p>This is the string
which the target MOB (if it is a MOB)
will see should the event occur successfully. If there is no target,
this string is null.</p>
        </li>
        <li> Others Code
          <p>This is an encoded
integer which represents how any other
objects (such as MOBs, Items, Rooms, Exits) other than the source and
target, in the same room, perceive the event. If the event is
completely imperceptible by anything other than the source, it may be 0
(CMMsg.NOEFFECT)</p>
        </li>
        <li> Others Message
          <p>This is the string
which other MOBs in the same room as
the source and target MOBs will see should the event occur
successfully. If the event is completely imperceptible by other MOBs,
it may be null.</p>
        </li>
      </ul>
      <p>The Source Code, Target
Code, and Others Code is easily the
most complicated aspect of a Message. For this reason, numerous
pre-configured message codes have been created in the CMMsg interface,
all of which begin with the characters MSG_. Although we will not go
into the meaning of each of these messages (that will be left to the
reader to search the code for instances of messages which use the
codes, and learn from the context in which they are used), we can at
least break down these codes so that they can be better understood.</p>
      <p>These coded integers all
have two parts, the Major aspect (or
the Major Code) and the Minor aspect (or the Minor Code). They may be
referenced off of an already constructed CMMsg object using such
methods as <code>sourceMajor()</code>
and <code>sourceMinor()</code>.
These methods will automaticallyy break down a <code>sourceCode()</code>
into the components we will discuss.</p>
      <p>The Major code is a
series of significant bits in the integer,
each of which gives some new meaning to the message. These bits are as
follows:</p>
      <a name="majorcode" id="majorcode"> </a>
      <table bgcolor="#ffccff" border="1">
        <thead> <tr>
          <th width="15%">Bit
mask</th>
          <th width="30%">CMMsg
Equate Variable(s)</th>
          <th>Meaning</th>
        </tr>
        </thead> <tbody>
          <tr>
            <td>2048</td>
            <td>
            <p>MASK_HANDS</p>
            </td>
            <td>Message includes
small movements.</td>
          </tr>
          <tr>
            <td>4096</td>
            <td>
            <p>MASK_MOVE</p>
            </td>
            <td>Message includes
large, full-body movements.</td>
          </tr>
          <tr>
            <td>8192</td>
            <td>MASK_EYES</td>
            <td>Message includes
visual information.</td>
          </tr>
          <tr>
            <td>16384</td>
            <td>MASK_MOUTH</td>
            <td>Message include
mouth movement, or consumption.</td>
          </tr>
          <tr>
            <td>32768</td>
            <td>MASK_SOUND,
MASK_SOUNDEDAT</td>
            <td>Message includes
auditory information.</td>
          </tr>
          <tr>
            <td>65536</td>
            <td>MASK_ALWAYS</td>
            <td>Override mask
which flags the message as something
which Must occur, regardless of the state of the source or target.</td>
          </tr>
          <tr>
            <td>131072</td>
            <td>MASK_MAGIC</td>
            <td>Message has a
magical nature.</td>
          </tr>
          <tr>
            <td>262144</td>
            <td>MASK_DELICATE</td>
            <td>Message includes
very fine, delicate movements, such as
thief skills.</td>
          </tr>
          <tr>
            <td>524288</td>
            <td>MASK_MALICIOUS</td>
            <td>Message represents
an attack of some sort.</td>
          </tr>
          <tr>
            <td>1048576</td>
            <td>MASK_CHANNEL</td>
            <td>Message is part of
public channel conversation.</td>
          </tr>
          <tr>
            <td>2097152</td>
            <td>MASK_OPTIMIZE</td>
            <td>Message
implementation should be optimized for
repetition.</td>
          </tr>
          <tr>
            <td>4194304</td>
            <td>MASK_CNTRLMSG</td>
            <td>Message
implementation is entirely internal system
message.</td>
          </tr>
          <tr>
            <td>8388608</td>
            <td>MASK_INTERMSG</td>
            <td>Message denotes an
action that is part of a final
larger action.</td>
          </tr>
        </tbody>
      </table>
      <p>The above masks can be
quite confusing. It is best to examine
the several MSG_ equates in the CMMsg interface to see how they are
properly or improperly used. Remember a MSG_ equate is a completely
constructed Code, complete with the appropriate Major and Minor aspects.</p>
      <p>The Minor Code represents
the more specific activity being
performed, and is a simple integer ranging from 0 (NO EFFECT) to 2047.
The officially recognized Minor codes are exhaustively listed in the
CMMsg interface, and all begin with the prefix TYP_. These types cover
every sort of major event which occurs in the CoffeeMud engine,
including getting items, casting spells, entering or leaving rooms,
etc, etc..</p>
      <pre>CMMsg msg = CMClass.getMsg(attacker,target,weapon,CMMsg.MSG_WEAPONATTACK,<br /> "&lt;S-NAME&gt;attack(s) &lt;T-NAME&gt;!");<br /></pre>
      <p>The core.CMClass has many
different getMsg signatures to make
message construction quick and painless. The above is an example where
only a single Code and a single message text are provided. In
constructors where only one Code or message text field are provided, it
is assumed that the code and message texts will be the same for source,
target (if any) and others.</p>
      <p>CMMsg objects also have <code>value()</code>
and <code>setValue(int)</code>
methods for modifying an integer not found in the constructor. This
number is used for several different purposes in message construction,
from the amount of damage in a TYP_DAMAGE message, to the amount of
experience in a TYP_EXPCHANGE message. This number is also used to
determine whether or not a standard saving throw was made. Value
defaults to 0, but, after running through a message which contains a
savable event, the value will be &gt;0 if the save was made.</p>
      <h3><a name="messagepreview" id="messagepreview">Message
Previewing</a></h3>
      <p>Once a Message has been
constructed, it is time to actually
put the message out into the system. There is a standard form for the
sending of almost all messages. If the source of the message is a MOB
called "SourceMOB", this standard form looks like this:</p>
      <pre>CMMsg msg = CMClass.getMsg(SourceMOB,TargetMOB,weapon,CMMsg.MSG_WEAPONATTACK, "&lt;S-NAME&gt;attack(s) &lt;T-NAME&gt;!");<br /><br />if(SourceMOB.location().okMessage(SourceMOB,msg))<br />{<br /> SourceMOB.location().send(SourceMOB,msg);<br />}<br /></pre>
      <p>The <code>location()</code>
field on a MOB refers to the Room
in which the mob is. Room's are always the top level at which messages
are previewed, and then executed or sent. The first line (where the
message is constructed) has already been examined. The second line, in
which the Room method <code>okMessage()</code>
is called, is the
preview step. In this step, the message is evaluated before it actually
happens. The first parameter to <code>okMessage()</code>
is called the "host" object, and it refers to the object to which the
one you are sending the message should refer back to. This parameter is
rarely used, except by Behaviors, and it is always safe to use the
source of your message as this value. The second parameter to <code>okMessage()</code>
is the message we constructed. The third line, where the Room <code>send()</code>
method is called, is the execution step.</p>
      <p>In the preview step, the
room object will examine the message
to see if there is anything which it might not like, wish to modify, or
wish to flag about the Message it has been handed. If the Room object
does not like the message, it will return false. Returning false from <code>okMessage()</code>
is always an order to cancel, and not execute the message. Under any
other circumstances, true may be returned to allow the message to go
forward. The Room will also make calls to the <code>okMessage()</code>
methods on every other MOB in the room, Exit from the room, Item in the
room, spell effects which may be on the room, and behaviors of the
room. The MOB who receives the <code>okMessage()</code>
call will, in
turn, pass the Message to the <code>okMessage()</code>
methods in
every Item the MOB is carrying or wearing, every spell effect on the
MOB, and every behavior of the MOB. Items wills also make <code>okMessage()</code>
calls on their spell effects. Any of these calls may modify or flag the
message they receive. Any of these calls may also return false. If any
object which previews a message returns false, the Room <code>okMessage()</code>
method will also return false, ordering the message to be totally
canceled. For this reason, <code>okMessage()</code>
methods are
careful about returning true unless they have a really good reason not
to.</p>
      <p>Inside the <code>okMessage()</code>
methods of every Item,
MOB, Behavior, Ability (spell effect), Exit, and Room the Messages may
(as we mentioned) be examined and modified, flagged, or canceled. As we
have already covered how Messages are canceled (by returning false).
Let us turn now to the manner in which Messages are modified or flagged.</p>
      <h3><a name="messageflagging" id="messageflagging">Message
Flagging and Modification</a></h3>
      <p>Message modification is
very rare. When it happens though, it
is done by calling one of the several <code>modify()</code>
methods on the Common.interfaces.CMMsg object. These methods allow the
source, target, and all other fields to be updated. Message
modification should also happen during the preview step so that any
changes made to the message are made before the message is executed. It
is also often wise, after making a change to a message, to recursively
call the okMessage method on the room again so that the modifications
can be previewed, but this is not always necessary.</p>
      <p>Message flagging is
somewhat less rare. Messages may be
flagged when a combat strike is successful, or when a saving throw is
made against a spell Effect, or for any other reason the Message
constructing code may wish. Flagging is done by calling the
aforementioned <code>CMMsg.setValue(int)</code>
method, and using it
to change the value to something other than the default of 0. Flagging
using the <code>setValue()</code>
method lets the code which constructed the Message know that something
significant with relation to the Message has occurred. The meaning of
this value will vary depending upon the type of message being
generated, and upon the purpose to which the creator of the message
wishes to put it. The value is read using the <code>int
value()</code>
method on CMMsg.</p>
      <h3><a name="messageexecution" id="messageexecution">Message
Execution</a></h3>
      <p>Once the <code>okMessage()</code>
method on a Room object has
returned true, and any code which may need to check or handle
modifications to the Message have executed, the Message is sent. The
proper way to send a Message is through the Room objects, by calling
one of the following Messages: <code>Room.send(MOB
SourceMOB, CMMsg
msg)</code> or <code>Room.sendOthers(MOB
SourceMOB, CMMsg msg)</code>.
The first method handles a standard Execution, while the second allows
every relevant object except the SourceMOB to handle Execution. The
first method should almost always be called.</p>
      <p>The <code>send()</code>
methods will then begin calling other
methods in other objects. These other methods are called the <code>executeMsg()</code>
methods, and are usually of the form <code>public
void
executeMsg(Environmental myHost, CMMsg msg);</code>.
These methods are
responsible for Executing the contents of the message. The Room method
will make <code>executeMsg()</code>
method calls on itself, and on
every Exit, Item, MOB, spell effects (Ability object), and Behavior
associated with that Room. As in the <code>okMessage()</code>
case,
the MOBs will in turn call the <code>executeMsg()</code>
methods on
their own Items and spell effects. Items will then call the <code>executeMsg()</code>
methods on their own spell effects, and so on.</p>
      <p>Of course, not every
object in your game will handle and react
to the Execution of every Message sent. Most of the time, a given
object will be ignoring the Message altogether. However, each object
knows precisely which Messages are important for it, and watch
carefully for them in both their <code>okMessage()</code>
and <code>executeMsg()</code>
methods. In general, every Message which is previewed in an objects <code>okMessage()</code>
method is handled in the <code>executeMsg()</code>
method of the same object, though this is by no means always true. In
general, the following object types handle the following types of
Messages:</p>
      <ul>
        <li> MOBs
          <p>Any Message which has
the mob instance as a target is both
Previewed and Executed. Any Message which has the mob as a source is
typically Previewed, and (lacking a target) may also be Executed.</p>
        </li>
        <li> Items
          <p>Any Message which has
the item instance as a target.</p>
        </li>
        <li> Exits
          <p>Any Message which has
the exit instance as a target or
tool.</p>
        </li>
        <li> Rooms
          <p>Any Message which has
the room instance as a target.</p>
        </li>
        <li> Ability(spell
effects)
          <p>Any Message
pertaining to the MOB or Item which is
affected by the spell or skill.</p>
        </li>
        <li> Behavior
          <p>Any Message
pertaining to the object instance which has
this behavior.</p>
        </li>
      </ul>
      <p>Now that you are
completely confused, it will make you at
least a bit happier to know that Room objects have several short-cut
methods for creating, previewing, and executing messages. They include
the following:</p>
      <pre>public boolean show( MOB source,<br /> Environmental target,<br /> int allCode,<br /> String allMessage<br /> );<br /><br />public boolean show( MOB source,<br /> Environmental target,<br /> Environmental tool,<br /> int allCode,<br /> String allMessage<br /> );<br /><br />public boolean show( MOB source,<br /> Environmental target,<br /> Environmental tool,<br /> int srcCode,<br /> int tarCode,<br /> int othCode,<br /> String allMessage<br /> );<br /><br />public boolean show( MOB source,<br /> Environmental target,<br /> Environmental tool,<br /> int srcCode,<br /> String srcMessage,<br /> int tarCode,<br /> String tarMessage,<br /> int othCode,<br /> String othMessage<br /> );<br /><br />public boolean show( MOB source,<br /> Environmental target,<br /> Environmental tool,<br /> int allCode,<br /> String srcMessage,<br /> String tarMessage,<br /> String othMessage<br /> );<br /><br />public boolean showOthers( MOB source,<br /> Environmental target,<br /> int allCode,<br /> String allMessage<br /> );<br /><br />public boolean showOthers( MOB source,<br /> Environmental target,<br /> Environmental tool,<br /> int allCode,<br /> String allMessage<br /> );<br /><br />public boolean showSource( MOB source,<br /> Environmental target,<br /> int allCode,<br /> String allMessage<br /> );<br /><br />public boolean showSource( MOB source,<br /> Environmental target,<br /> Environmental tool,<br /> int allCode,<br /> String allMessage<br /> );<br /><br />public void showHappens(int allCode, String allMessage);<br /><br />public void showHappens( int allCode,<br /> Environmental like,<br /> String allMessage<br /> );<br /></pre>
      <p>The first methods (show)
is very commonly used; it constructs
a message with the given source and target (no tool), and with the
given Code and text message applying to source, target, and others. The
      <code>showHappens()</code>
methods will do the same, but will also construct a blank MOB object to
act as the source, for those instances where a source MOB is not
readily available. The <code>showOthers()</code>
methods behave like
the first, but do not allow the source MOB to preview or execute the
message, while the <code>showSource()</code>
methods ONLY allows the
source MOB to preview and execute the message.</p>
      <p>All four of those methods
will construct a CMMsg object, give
the Message to the Room object for previewing ("okMessage"), and then,
if the Message is not canceled, will call the Room "send" method for
execution and return true. If the Message was canceled, false will be
returned.</p>
      <h3><a name="messagetrailers">Message Trailers</a></h3>
      <p>The final subject we will
discuss in the area of Messages and
Message handling regards another rare technique called Message Trailer
adding. Message Trailers are CMMsg objects which have been added to
another CMMsg instance using the <code>CMMsg.addTrailerMsg(CMMsg
msg)</code>
method. The Message passed to this method is constructed in the usual
way. This method may be properly called at any point during the Preview
or Execution stage of Message handling, by any Previewing or Executing
object. When it is performed is not important, because any Messages
added using this method are not Previewed or Executed until after the
Room object has completely finished sending the host Message to all
interested objects.</p>
      <p>Constructing and adding
messages which act as message trailers
can serve many purposes, but the most important of which is that the
trailer messages only happen IF the host message also happens, and only
happen AFTER the host message happens. This can be useful for the
timing of subsequent messages which are dependent on others.</p>
      <img src="images/temple.jpg" alt="The State of Things" />
      <h2><a name="DIG2" id="DIG2">Core Topic 2: The State
of Things:</a></h2>
      <p>In most systems, it is
typical for all of the data variables
which describe a particular object to be coded directly inside that
object. While this is also true in CoffeeMud, many important data
fields, along with the appropriate "getter" and "setter" methods, are
stored in separate special data-storage, or state objects. These
data-storage objects provide access to numerous important properties
for those objects. These storage/state objects are routinely copied and
then the copies are modified by other objects which have a spacial
relationship with them. For instance, a MOB object may copy one or more
of its state objects, and then allow the local Room object, or his
inventory Item objects, or spell Effect objects to modify the copy, The
copied state object modifications are stacked on each other. Confused?
Well, keep reading!</p>
      <p>Each instance of the
several Physical objects (MOBs,
Items, Exits, Rooms) have a particular storage/state object called
their Physical Stats. This object implements the
Common.interfaces.PhyStats interface, and is typically an instance of
the Common.DefaultPhyStats class. Access to this state object is
available through each core.interfaces.Physical objects <code>PhyStats
basePhyStats()</code> and <code>PhyStats
phyStats()</code> method
calls. Since Rooms, MOBS, Items, Exits, and Areas are all Physical
objects, that means that they all have basePhyStats and phyStats
methods as well.</p>
      <h3><a name="phystats" id="phystats">PhyStats state
object fields</a></h3>
      <table bgcolor="#ccccff" border="1">
        <thead> <tr>
          <th>Field name</th>
          <th>Relevant objects</th>
          <th>Meaning</th>
        </tr>
        </thead> <tbody>
          <tr>
            <td>level</td>
            <td>Item, MOB, Exit</td>
            <td>Experience level
(see Archon's Guide)</td>
          </tr>
          <tr>
            <td>ability</td>
            <td>Item, MOB</td>
            <td>Magical level (see
Archon's Guide)</td>
          </tr>
          <tr>
            <td>rejuv</td>
            <td>Item, MOB</td>
            <td>Rejuvenation rate
(see Archon's Guide)</td>
          </tr>
          <tr>
            <td>weight</td>
            <td>Item, MOB</td>
            <td>Weight of the
object</td>
          </tr>
          <tr>
            <td>height</td>
            <td>Armor, MOB</td>
            <td>Size of the object</td>
          </tr>
          <tr>
            <td>armor</td>
            <td>Item, MOB</td>
            <td>Protection level
(see Archon's Guide)</td>
          </tr>
          <tr>
            <td>damage</td>
            <td>Item, MOB</td>
            <td>Damaging ability</td>
          </tr>
          <tr>
            <td>speed</td>
            <td>Item, MOB</td>
            <td>Attack speed</td>
          </tr>
          <tr>
            <td>attackAdjustment</td>
            <td>Item, MOB</td>
            <td>Attack level</td>
          </tr>
          <tr>
            <td>replacementName</td>
            <td>Item, MOB, Exit</td>
            <td>New displayable
name of the object</td>
          </tr>
          <tr>
            <td>sensesMask</td>
            <td>Item, MOB, Exit,
Room</td>
            <td>Bit mask of
relevant sensory abilities.</td>
          </tr>
          <tr>
            <td>disposition</td>
            <td>Item, MOB, Exit,
Room</td>
            <td>Bit mask of
relevant disposition state</td>
          </tr>
        </tbody>
      </table>
      <p>Although most of these
fields are better described in the
Archon's Guide, there are two whose nature may not be readily apparent:
the sensesMask and the disposition. These two integers are bitmaps. The
value of each bit is defined by equates in the
Common.interfaces.PhyStats interface. The equates which refer to the
bits for sensesMask all begin with "CAN_" for MOBs or "SENSE_" for
non-MOBs, while the equates which
refer to the bits for disposition all begin with "IS_".</p>
      <p>Now, as mentioned
previously, all Physical objects have
two methods for accessing their PhyStats. One is <code>core.interfaces.Physical.basePhyStats()</code>
and the other is <code>core.interfaces.Physical.phyStats()</code>.
The difference between these two methods is very significant. The
PhyStats state object returned by the "basePhyStats" method refers to
the permanent, unmodified, "base" state of the Physical object.
The "phyStats" method, however, returns the modified, less permanent,
"current" state of the Physical object. The PhyStats object
returned by the "phyStats" method is always copied and derived from the
"basePhyStats" values, after all relevant modifications have been made
to it. How the current state object goes from its base values
(basePhyStats) to its current values (phyStats) is our next topic.</p>
      <p>We must now introduce two
other Physical interface
methods significant to this topic. One is the <code>recoverPhyStats()</code>
method, while the other is the <code>affectPhyStats(Physical
affected, PhyStats affectableStats)</code>
method. The
"recoverPhyStats" method is also located on every Physical (Item,
MOB, Exit, etc) object and is the method which turns the <code>basePhyStats()</code>
values into their current <code>phyStats()</code>
values. This method call works by copying the base values into the
current values and then allowing certain other objects to have an
opportunity to affect the copy. Only after all opportunities to modify
the copied values have been exhausted, does the <code>recoverPhyStats()</code>
method return. In essence, <code>recoverPhyStats()</code>
allows the
Physical objects <code>basePhyStats()</code>
to be updated, with
that updated state object made available through <code>phyStats()</code>.</p>
      <p>The way in which the
current PhyStats state object is modified
by the <code>recoverPhyStats()</code>
method call is by making
repeated internal calls to the <code>affectPhyStats(Physical
affected, PhyStats affectedStats)</code>
methods on other relevant objects. These methods will then have the
opportunity to change the values in the current state object
(affectedStats parameter) however they wish. The relevant objects which
may change the state of an Physical are as follows:</p>
      <ul>
        <li> MOBs
          <p>Room object being
occupied, something being Ridden, the
MOBs Character Class object, the MOBs Race object, the Items in the
MOBs inventory, and finally the Ability objects which are affecting the
MOB (spell effects).</p>
        </li>
        <li> Items, Exits, Areas
          <p>Ability objects which
are affecting it (spell effects).</p>
        </li>
        <li> Rooms
          <p>Area object which
this room is a part of, Ability objects
which are affecting it (spell effects), Items in the Room, and MOBs in
the Room.</p>
        </li>
      </ul>
      <p>Here is an example:</p>
      <p>Gunker the Thief wears
Full Plate Armor (Item), and has the
Shield spell cast on him. His base Armor rating is 100. When he puts on
the Plate Armor, the "recoverPhyStats" method is called on Gunker's MOB
object. That method in turn calls the "affectPhyStats" method on the
Plate Armor and the Shield spell Effect. Both of those methods improve
the Armor rating on Gunker's MOB's current PhyStats by some number.
Thus, Gunker becomes harder to hit in combat. Also, when Gunker picked
up the Plate armor, the weight of the armor was added to Gunker's
overall carried weight by increasing the weight value in Gunker's
PhyStats object.</p>
      <p>I know, this is probably
still confusing.</p>
      <p>Confusing or not,
however, we still have to consider two other
state objects, both of which are only available from the MOB object.
One of which is the CharStats object, and the other of which is the
CharState object.</p>
      <p>The CharStats objects are
most closely analogous to the
PhyStats objects. For instance, there are <code>CharStats
baseCharStats()</code> and <code>CharStats
charStats()</code> method
calls from a MOB object, as well as a <code>recoverCharStats()</code>
method call. All of these work similarly to the ones described above
for PhyStats. The fields on a Common.interfaces.CharStats object are
somewhat more straight forward however. Most of the fields of a
CharStats object are referenced using the <code>int
getStat(int)</code>
and <code>setStat(int,int)</code>
methods on a CharStats object. Both of these methods require, as their
first parameter, an integer code which corresponds to the specific stat
being set or read. These stat parameters are defined as equates within
the CharStats interface, and include:</p>
      <p><a name="charstats" id="charstats">STAT_STRENGTH,
STAT_INTELLIGENCE, STAT_DEXTERITY, STAT_CONSTITUTION, STAT_CHARISMA,
STAT_WISDOM, STAT_GENDER, STAT_SAVE_PARALYSIS, STAT_SAVE_FIRE,
STAT_SAVE_COLD, STAT_SAVE_WATER, STAT_SAVE_GAS, STAT_SAVE_MIND,
STAT_SAVE_GENERAL, STAT_SAVE_JUSTICE, STAT_SAVE_ACID,
STAT_SAVE_ELECTRIC, STAT_SAVE_POISON, STAT_SAVE_UNDEAD,
STAT_SAVE_MAGIC, STAT_SAVE_DISEASE, STAT_SAVE_TRAPS,
STAT_MAX_STRENGTH_ADJ, STAT_MAX_INTELLIGENCE_ADJ,
STAT_MAX_DEXTERITY_ADJ, STAT_MAX_CONSTITUTION_ADJ,
STAT_MAX_CHARISMA_ADJ, STAT_MAX_WISDOM_ADJ, STAT_AGE,
STAT_SAVE_DETECTION, STAT_SAVE_OVERLOOKING.</a></p>
      <p>In addition to these
equates defined and read through the <code>getStat()</code>
and <code>setStat()</code>
methods, there is also the Race object
available through <code>getMyRace()</code>
and <code>setMyRace()</code>
methods, as well as Character Class and Character Class level methods.
See the Common.interfaces.CharStats java file for more information on
those methods and how they work.</p>
      <p>Like the PhyStats above,
those objects listed as able to
modify the PhyStats current state object are the same objects which are
able to modify the CharStats state objects. Rereading the section on
PhyStats will make clear how the CharStats objects are modified in the
same analogous manner, using repeated calls to<code>
affectCharStats(MOB affected, CharStats affectedStats)</code>
methods
on related objects.</p>
      <p><a name="charstate" id="charstate"> The last
state object
to consider is the Common.interfaces.CharState objects on MOBs. The
CharState object represents those fields which are constantly in flux:
Hit Points, Mana, Movement, Hunger, Fatigue, and Thirst.</a></p>
      <p>Unlike PhyStats and
CharStats, there are three CharState
objects to consider for MOBs: the base CharState object (available
through <code>CharState
baseState()</code> method, the
adjusted base
CharState (or max state) object available through the <code>CharState
maxState()</code> method and
modified by <code>recoverMaxState(MOB
affected, CharState affectedState)</code>
methods on related objects,
and lastly the current CharState object available through the <code>CharState
curState()</code> and refreshed or
reset to maximums using the MOBs <code>resetToMaxState()</code>
method.</p>
      <p>The relationship between
the above objects is as follows: The
base CharState object represents the maximum values for the state
variables BEFORE modification by magical armor or spells. The adjusted
base CharState object (Max State) represents the maximum values for the
state variables AFTER modification by magical armor or spells. The
current CharState object (curState) represents the current hit points,
mana points, etc available to the MOB.</p>
      <p>In the case of the
CharState objects, adjustment by relevant
objects is initiated by calling the MOBs <code>recoverMaxState()</code>
method. This method allows the same objects who modify the PhyStats and
CharStats above to modify the maximum CharState values as well.</p>
      <p>Once again, to understand
one of them fully is to understand
them all.</p>
      <img src="images/time.jpg" alt="Tick Tock" />
      <h3><a name="DIG3" id="DIG3">Core Topic 3: Tick Tock</a></h3>
      <p>Our next Core Topic will
cover the ability of the mobs, items,
exits, abilities, spell effects, behaviors, and other objects to
perform tasks on a regular, timed, basis. The tasks to be performed are
always located within an method called <code>boolean
tick(Tickable
ticking, int tickID)</code>. All
Environmental objects define this
method, and Behavior objects do as well.</p>
      <p>These methods are called
on a regular, timed basis whenever
the object instance in question has been properly set up to do so, and
at a defined frequency and interval. The "ticking" parameter is usually
a reference to the object itself, or to the host object in the case of
Behaviors. The "tickID" parameter describes what sort of regular timed
event is occurring. These events are defined as equates in the
core.interfaces.Tickable interface, and include IDs such as TICKID_MOB,
TICKID_AREA, TICKID_EXIT_REOPEN and others. See the java file of that
interface for more defined tickID values.</p>
      <p>Before we get into the
methods by which an object instance are
properly set up for regular calls to its <code>tick()</code>
method, it may be worthwhile to discuss which regular ticks are setup
by the system by default. These tick events cover the most commonly
used objects under the most common circumstances, and so may be just
the events you already needed! They include:</p>
      <ul>
        <li> MOBs
          <p>All MOBs have their <code>tick()</code>
method called
once per CMProps.getTickMillis() (4 seconds), with the "tickID" defined
by&nbsp;Tickable.MOB_TICK. MOBs will, in turn, call the <code>tick()</code>
methods on their own Behaviors, and Ability objects affecting them. If
any of these dependent objects return "false" from their own tick
methods, then the object will cease to receive any further tick method
calls.</p>
        </li>
        <li> Exits, Items, Rooms
          <p>Whenever a Behavior
is added to any of these objects, they
will begin to have their tick methods called once
per&nbsp;CMProps.getTickMillis()
(4 seconds), with the tickID defined by Tickable.TICKID_ITEM_BEHAVIOR,
TICKID_EXIT_BEHAVIOR, or TICKID_ROOM_BEHAVIOR. Deletion of the last
behavior from the host object will stop this tick event from occurring
again.</p>
        </li>
        <li> Areas
          <p>All Area objects have
their tick methods called once
per&nbsp;CMProps.getTickMillis(), with the tickID defined by
Tickable.TICKID_AREA.</p>
        </li>
        <li> Ability
          <p>Whenever an Ability
object is added as an Effect (using
the <code>addEffect()</code>
Physical method) to a non-MOB object by using the proper Ability
invoke procedure (see below), then the Ability object itself will gain
it's own regular calls to its tick method. The tickID for this call is
also Tickable.TICKID_MOB, so as to make consistant the tickID for all
spell and similar effects.</p>
        </li>
      </ul>
      <p>To sum up, MOBs have
regular tick calls which they use to
perform their own periodic tasks, as well as to allow their Behavior
and spell effects to perform tasks. The other objects have
circumstantial ticks in certain instances.</p>
      <p>Now, to add a new
periodic call to the "tick" method on an
Environmental object, one needs only to make a method call like this:</p>
      <pre>CMClass.threads().startTickDown(theEnvObject,Tickable.MY_TICK_ID,CMProps.getTickMillis(),NUM_TICKS);<br /></pre>
      <p>The second parameter is
the tickID which will be used when the <code>tick()</code>
method on the "theEnvObject" object is called. The third parameter is
the time interval, in milliseconds, between each event. The fourth
parameter is the number of time intervals between each call to the <code>tick()</code>
method. The total time between each call to the <code>tick()</code>
method, therefore, will be&nbsp;&nbsp;CMProps.getTickMillis() *
NUM_TICKS.</p>
      <p>Now, the above version of <code>startTickDown()</code>
can be
used to create timed events of any duration. However, all objects in
the base distribution of CoffeeMud operate on a single default time
interval, usually of 4000 milliseconds, as defined by
CMProps.getTickMillis() and ultimately from the coffeemud.ini file. For
this reason, a different version of the <code>startTickDown()</code>
method is called which does not include the time parameter,
utilizing the standard delay instead:</p>
      <pre>CMClass.ThreadEngine().startTickDown(theEnvObject,Host.MY_TICK_ID,NUM_TICKS);<br /></pre>
      <p>Stopping any of these
tick calls can be done by simply
returning "false" from the tick method itself, or manually using the
following:</p>
      <pre>CMClass.ThreadEngine().deleteTick(theEnvObject,Host.MY_TICK_ID);<br /></pre>
      <p>You may also stop tick
calls to an object by using the
Environmental objects <code>destroy()</code>
method.</p>
      <img src="images/books.jpg" alt="Core Libraries" />
      <h2><a name="DIG4" id="DIG4">Core Topic 4: Core
Libraries</a></h2>
      <p>The CoffeeMud engine
contains numerous Java classes whose
purpose is to perform much of the underlying game functionality. Some
of these Java classes are Core classes, some are Library classes, and
some are Common classes.</p>
      <p>Core classes are those
classes found in the
com.planet_ink.coffee_mud.core package. Like the interfaces, they may
not be extended or overwritten without risking problems. The core
classes, and their general purpose is:</p>
      <a name="corepurpose" id="corepurpose"> </a>
      <table bgcolor="#ffffcc" border="1">
        <thead> <tr>
          <th>Core Class Name</th>
          <th>Purpose</th>
        </tr>
        </thead> <tbody>
          <tr>
            <td>B64Encoder</td>
            <td>Encode and decode
text&lt;-&gt;binary using Base64</td>
          </tr>
          <tr>
            <td>CMath</td>
            <td>Converting strings
to numbers, performing bit-wise and
other arithmetic operations</td>
          </tr>
          <tr>
            <td>CMClass</td>
            <td>Main ClassLoader
-- get all your objects from methods
here!</td>
          </tr>
          <tr>
            <td>CMFile</td>
            <td>FileSystem
manager, get all your file data from this
class</td>
          </tr>
          <tr>
            <td>CMLib</td>
            <td>The non-core
library reference object. * See below for
more information.</td>
          </tr>
          <tr>
            <td>CMParms</td>
            <td>Methods for
parsing strings and determining parameter
values in many different ways.</td>
          </tr>
          <tr>
            <td>CMProps</td>
            <td>Properties
manager, for reading INI file values from
coffeemud.ini and other places.</td>
          </tr>
          <tr>
            <td>CMSecurity</td>
            <td>The security
manager, for evaluating player and system
security flags.</td>
          </tr>
          <tr>
            <td>CMStrings</td>
            <td>Methods to
manipulate, pad, and filter strings.</td>
          </tr>
          <tr>
            <td>Directions</td>
            <td>Methods to handle
the different compass directions.</td>
          </tr>
          <tr>
            <td>Log</td>
            <td>The file and
console logging manager.</td>
          </tr>
          <tr>
            <td>MiniJSON</td>
            <td>A JSON text
document parser</td>
          </tr>
          <tr>
            <td>Resources</td>
            <td>The
object-resource manager, usually with lots of
StringBuffers keyed by String names.</td>
          </tr>
        </tbody>
      </table>
      <p>You should check out the
javadocs for those classes for more
information on the core classes.</p>
      <p>* CMLib also refers to
some of the sub-core classes, such as
the Database access objects, and the Threading engine. While they are
considered core, they are accessed through CMLib as if they were
non-core libraries. Most core classes can also be accessed through
CMLib methods, making it a one-stop shop.</p>
      <p>Now, non-core libraries,
or Libraries proper, are located in
the com.planet_ink.coffee_mud.Libraries package, and each one
implements a unique interface from the
com.planet_ink.coffee_mud.Libraries.interfaces package. This is unique,
that each class in the Libraries package implements a unique interface
all its own, but that is not the only unique thing about this package.
Libraries are also singletons -- there is never more than 1 instance of
each Library. Moreover, these singletons are all accessed from a single
accessor class, CMLib, which we mentioned earlier.</p>
      <p>Here is a map of how the
classes, interfaces, and CMLib
methods are all mapped together:</p>
      <a name="corelibrarymap" id="corelibrarymap"> </a>
      <table bgcolor="#99ff99" border="1">
        <thead> <tr>
          <th>Library class name <code>...Libraries.*</code> </th>
          <th>Library interface
name <code>...Libraries.interfaces.*</code> </th>
          <th>CMLib method name <code>...core.CMLib</code> </th>
          <th>Purpose of the
Library</th>
        </tr>
        </thead> <tbody>
          <tr>
            <td>AutoTitles</td>
            <td>AutoTitlesLibrary</td>
            <td><code>titles()</code></td>
            <td>Automatic player
vanity titles</td>
          </tr>
          <tr>
            <td>Achievements</td>
            <td>AchievementLibrary</td>
            <td><code>achievements()</code></td>
            <td>Player achievments
system</td>
          </tr>
          <tr>
            <td>BeanCounter</td>
            <td>MoneyLibrary</td>
            <td><code>beanCounter()</code> </td>
            <td>Handle money and
currency.</td>
          </tr>
          <tr>
            <td>CharCreation</td>
            <td>CharCreationLibrary</td>
            <td><code>login()</code> </td>
            <td>Login and create
new players.</td>
          </tr>
          <tr>
            <td>Clans</td>
            <td>ClanManager</td>
            <td><code>clans()</code> </td>
            <td>Handle all clans.</td>
          </tr>
          <tr>
            <td>CMAbleMap</td>
            <td>AbilityMapper</td>
            <td><code>ableMapper()</code> </td>
            <td>Maps CharClasses
to Skills/Abilities.</td>
          </tr>
          <tr>
            <td>CMAbleComps</td>
            <td>AbilityComponents</td>
            <td><span style="font-family: monospace;">ableComponents()</span></td>
            <td>Manages Skill
Components</td>
          </tr>
          <tr>
            <td>CMAbleParms</td>
            <td>AbilityParameters</td>
            <td><span style="font-family: monospace;">ableParms()</span></td>
            <td>Editors for
Ability recipes/parms</td>
          </tr>
          <tr>
            <td>CMCatalog</td>
            <td>CatalogLibrary</td>
            <td style="font-family: monospace;">catalog()</td>
            <td>Manages cataloged
mobs and items</td>
          </tr>
          <tr>
            <td>CMChannels</td>
            <td>ChannelsLibrary</td>
            <td><code>channels()</code> </td>
            <td>Handles public
channels.</td>
          </tr>
          <tr>
            <td>CMColor</td>
            <td>ColorLibrary</td>
            <td><code>color()</code> </td>
            <td>ANSI and color
code conversions.</td>
          </tr>
          <tr>
            <td>CMEncoder</td>
            <td>TextEncoders</td>
            <td><code>encoder()</code> </td>
            <td>Compression
library.</td>
          </tr>
          <tr>
            <td>CMJournals</td>
            <td>JournalsLibrary</td>
            <td><code>journals()</code> </td>
            <td>Handles public
journal commands.</td>
          </tr>
          <tr>
            <td>CMGenEditor</td>
            <td>GenericEditor</td>
            <td><span style="font-family: monospace;">genEd()</span></td>
            <td>Command Line
editing prompts</td>
          </tr>
          <tr>
            <td>CMLister</td>
            <td>ListingLibrary</td>
            <td><code>lister()</code> </td>
            <td>Handles listing
tables nicely.</td>
          </tr>
          <tr>
            <td>CMMap</td>
            <td>WorldMap</td>
            <td><code>map()</code> </td>
            <td>Find areas and
rooms.</td>
          </tr>
          <tr>
            <td>CMPlayers</td>
            <td>PlayerLibrary</td>
            <td><code>players()</code></td>
            <td>Manage player lists</td>
          </tr>
          <tr>
            <td>CoffeeFilter</td>
            <td>TelnetFilter</td>
            <td><code>coffeeFilter()</code> </td>
            <td>Filters/transforms
text going to and from a player.</td>
          </tr>
          <tr>
            <td>CoffeeLevels</td>
            <td>ExpLevelLibrary</td>
            <td><code>leveler()</code> </td>
            <td>Leveling and
Experience gaining functionality.</td>
          </tr>
          <tr>
            <td>CoffeeMaker</td>
            <td>GenericBuilder</td>
            <td><code>coffeeMaker()</code> </td>
            <td>Generic Mob/Item
and CoffeeXML generators.</td>
          </tr>
          <tr>
            <td>CoffeeUtensils</td>
            <td>ProtocolsLibrary</td>
            <td><code>protocol()</code> </td>
            <td>Special protocol
support: MSP, MXP, MSDP, GMCP.</td>
          </tr>
          <tr>
            <td>CoffeeShops</td>
            <td>ShoppingLibrary</td>
            <td><code>coffeeShops()</code> </td>
            <td>Handles
manipulation of shop inventories.</td>
          </tr>
          <tr>
            <td>CoffeeTables</td>
            <td>StatisticsLibrary</td>
            <td><code>coffeeTables()</code> </td>
            <td>Maintains player
usage stats.</td>
          </tr>
          <tr>
            <td>CoffeeTime</td>
            <td>TimeManager</td>
            <td><code>time()</code> </td>
            <td>Real-life
date/time display.</td>
          </tr>
          <tr>
            <td>CoffeeUtensils</td>
            <td>CMMiscUtils</td>
            <td><code>utensils()</code> </td>
            <td>Misc stuff-- law,
traps, titles, resets.</td>
          </tr>
          <tr>
            <td>ColumbiaUniv</td>
            <td>ExpertiseLibrary</td>
            <td><code>expertises()</code></td>
            <td>Handle ability
expertise lists</td>
          </tr>
          <tr>
            <td>CommonMsgs</td>
            <td>CommonCommands</td>
            <td><code>commands()</code> </td>
            <td>Methods for
getting, talking, common-stuff</td>
          </tr>
          <tr>
            <td>Dice</td>
            <td>DiceLibrary</td>
            <td><code>dice()</code> </td>
            <td>Random number
generator.</td>
          </tr>
          <tr>
            <td>DirtyLanguage</td>
            <td>LanguageLibrary</td>
            <td><code>lang()</code></td>
            <td>Handle hl
translation rules</td>
          </tr>
          <tr>
            <td>EnglishParser</td>
            <td>EnglishParsing</td>
            <td><code>english()</code> </td>
            <td>Player command
line parsing helpers.</td>
          </tr>
          <tr>
            <td>Factions</td>
            <td>FactionManager</td>
            <td><code>factions()</code> </td>
            <td>Handles the
factions and faction system.</td>
          </tr>
          <tr>
            <td>GroundWired</td>
            <td>TechLibrary</td>
            <td><span style="font-family: monospace;">tech()</span></td>
            <td>Handles tech and
spacy stuff.</td>
          </tr>
          <tr>
            <td>MUDLaw</td>
            <td>LegalLibrary</td>
            <td><span style="font-family: monospace;">law()</span></td>
            <td>Handles legal and
property matters.</td>
          </tr>
          <tr>
            <td>MUDFight</td>
            <td>CombatLibrary</td>
            <td><code>combat()</code> </td>
            <td>Combat and Death
routines.</td>
          </tr>
          <tr>
            <td>MUDHelp</td>
            <td>HelpLibrary</td>
            <td><code>help()</code> </td>
            <td>Handling help-file
entries.</td>
          </tr>
          <tr>
            <td>MUDPercolator</td>
            <td>AreaGenerationLibrary</td>
            <td><span style="font-family: monospace;">percolator()</span></td>
            <td>Random area
generation library.</td>
          </tr>
          <tr>
            <td>MUDTracker</td>
            <td>TrackingLibrary</td>
            <td><code>tracking()</code> </td>
            <td>Methods for NPC
movement, and for tracking.</td>
          </tr>
          <tr>
            <td>MUDZapper</td>
            <td>MaskingLibrary</td>
            <td><code>masking()</code> </td>
            <td>Zapper-mask
parsing and evaluation.</td>
          </tr>
          <tr>
            <td>Polls</td>
            <td>PollManager</td>
            <td><code>polls()</code> </td>
            <td>Handle the public
polls.</td>
          </tr>
          <tr>
            <td>Quests</td>
            <td>QuestManager</td>
            <td><code>quests()</code> </td>
            <td>Quest Manager
system.</td>
          </tr>
          <tr>
            <td>RawCMaterials</td>
            <td>MaterialLibrary</td>
            <td><span style="font-family: monospace;">materials()</span></td>
            <td>Manipulate/Create
raw resource objects</td>
          </tr>
          <tr>
            <td>Sense</td>
            <td>CMFlagLibrary</td>
            <td><code>flags()</code> </td>
            <td>Sensory and
Disposition bitmap/flag handling.</td>
          </tr>
          <tr>
            <td>Sessions</td>
            <td>SessionsList</td>
            <td><code>sessions()</code> </td>
            <td>Container for
player connection objects.</td>
          </tr>
          <tr>
            <td>SlaveryParser</td>
            <td>SlaveryLibrary</td>
            <td><code>slavery()</code> </td>
            <td>Geas and Slavery
order parsing and execution.</td>
          </tr>
          <tr>
            <td>SMTPclient</td>
            <td>SMTPLibrary</td>
            <td><code>smtp()</code> </td>
            <td>E-Mail sending
routines.</td>
          </tr>
          <tr>
            <td>Socials</td>
            <td>SocialsList</td>
            <td><code>socials()</code> </td>
            <td>Socials container
and parser.</td>
          </tr>
          <tr>
            <td>StdLibrary</td>
            <td>NONE</td>
            <td>NONE</td>
            <td>SuperClass of
other libraries.</td>
          </tr>
          <tr>
            <td>TimsLibrary</td>
            <td>ItemBalanceLibrary</td>
            <td><code>itemBuilder()</code> </td>
            <td>Methods for
normalized item evaluation.</td>
          </tr>
          <tr>
            <td>WebMacroCreamer</td>
            <td>WebMacroLibrary</td>
            <td><code>webMacroFilter()</code> </td>
            <td>Web Server
extension for cmvp files.</td>
          </tr>
          <tr>
            <td>XMLManager</td>
            <td>XMLLibrary</td>
            <td><code>xml()</code> </td>
            <td>General XML
parsing.</td>
          </tr>
        </tbody>
      </table>
      <p>Libraries are lastly
unique in that it is almost useless to
write new ones, unless you are doing the most serious additions and
enhancements to your system. However, they are designed especially so
they they can be extended and overridden. They have their own entry in
the coffeemud.ini file called LIBRARY. By writing classes that extend
the base CoffeeMud library classes, and overriding their methods, you
can make changes to the most basic CoffeeMud algorithms, even at
run-time! Libraries also have an entry in the coffeemud.ini file,
LIBRARY, so that you can specify your custom extended versions of them
after the %DEFAULT% string, thus allowing your changes to be loaded at
boot-time.</p>
      <p>The last set of classes
to discuss under this topic are
neither Core class or Libraries, but form parts of the cores of other
classes, including many of the Libraries. These are the Common classes.
They are part of the com.planet_ink.coffee_mud.Common package. Like the
Libraries, they each implement their own unique interface from the
com.planet_ink.coffee_mud.Common.interfaces package. However, unlike
the Libraries, numerous instances of each class will exist in your mud,
and they are created from the core CMClass loader, much like MOBs,
Items, Rooms, and so forth. The javadocs are also a good place to learn
about these classes, but here is a brief list of them to wrap up our
last Core Topic.</p>
      <a name="corecommon" id="corecommon"> </a>
      <table bgcolor="#ccccff" border="1">
        <thead> <tr>
          <th>Common Class</th>
          <th>Description</th>
        </tr>
        </thead> <tbody>
          <tr>
            <td>AuctionCoffeeShop</td>
            <td>A special
derivative of DefaultCoffeeShop for
auctioneers</td>
          </tr>
          <tr>
            <td>DefaultAbilityComponent</td>
            <td>Describes a
component needed to use a skill.</td>
          </tr>
          <tr>
            <td>DefaultArrestWarrant</td>
            <td>An object created
every time a law is broken.</td>
          </tr>
          <tr>
            <td>DefaultAuction</td>
            <td>An object to store
the state information about an
ongoing auction.</td>
          </tr>
          <tr>
            <td>DefaultAuctionPolicy</td>
            <td>An object to grab
and manipulate auction house
policies, pricing, timing, etc</td>
          </tr>
          <tr>
            <td>DefaultCharState</td>
            <td>Contains a mobs
hit points, mana, movement, fatigue,
hunger, and thirst.</td>
          </tr>
          <tr>
            <td>DefaultCharStats</td>
            <td>Contains a mobs
class, race, saving throws, and basic
stat scores.</td>
          </tr>
          <tr>
            <td>DefaultClan</td>
            <td>Represents a
single Clan.</td>
          </tr>
          <tr>
            <td>DefaultClanPosition</td>
            <td>A rank within a
clan government.</td>
          </tr>
          <tr>
            <td>DefaultClanGovernment</td>
            <td>A clan government.</td>
          </tr>
          <tr>
            <td>DefaultClimate</td>
            <td>A single climatary
system for a given area.</td>
          </tr>
          <tr>
            <td>DefaultCoffeeShop</td>
            <td>Represents a
single shop store inventory.</td>
          </tr>
          <tr>
            <td>DefaultCoffeeTableRow</td>
            <td>Represents a days
worth of game player usage statistics.</td>
          </tr>
          <tr>
            <td>DefaultFaction</td>
            <td>Represents a
single faction.</td>
          </tr>
          <tr>
            <td>DefaultHttpClient</td>
            <td>Represents an
internal http/web page getter.</td>
          </tr>
          <tr>
            <td>DefaultItemCollection</td>
            <td>Represents an
external collection of standard Items</td>
          </tr>
          <tr>
            <td>DefaultJournalEntry</td>
            <td>Represents an
entry in a journal.</td>
          </tr>
          <tr>
            <td>DefaultLawSet</td>
            <td>Represents a
single set of laws and legal policies.</td>
          </tr>
          <tr>
            <td>DefaultManufacturer</td>
            <td>Represents a
manufacturer of technical/electronic items.</td>
          </tr>
          <tr>
            <td>DefaultMessage</td>
            <td>A CoffeeMud event
message (CMMsg).</td>
          </tr>
          <tr>
            <td>DefaultPhyStats</td>
            <td>Contains an
objects attack bonus, armor bonus, weight,
height, rejuv rate.</td>
          </tr>
          <tr>
            <td>DefaultPlayerAccount</td>
            <td>A characters base
account, if the account system is used</td>
          </tr>
          <tr>
            <td>DefaultPlayerStats</td>
            <td>Represents
player-specific fields like prompts,
friends, alias, etc.</td>
          </tr>
          <tr>
            <td>DefaultPoll</td>
            <td>A single poll
object.</td>
          </tr>
          <tr>
            <td>DefaultQuest</td>
            <td>Container for a
single timed quest.</td>
          </tr>
          <tr>
            <td>DefaultRoomnumberSet</td>
            <td>Container for a
players area visitation memory.</td>
          </tr>
          <tr>
            <td>DefaultScriptingEngine</td>
            <td>Engine for
executing MOBPROG scripts and maintaining
script variables</td>
          </tr>
          <tr>
            <td>DefaultSession</td>
            <td>Connection object
for handling a players telnet session
with the mud</td>
          </tr>
          <tr>
            <td>DefaultSocial</td>
            <td>Object for a
single social command.</td>
          </tr>
          <tr>
            <td>DefaultTattoo</td>
            <td>Object for a named
marker/flag with optional tick
lifespan.</td>
          </tr>
          <tr>
            <td>DefaultTimeClock</td>
            <td>Object
representing a single calendar/time system that
spans areas, possibly the whole world.</td>
          </tr>
          <tr>
            <td>FakeSession</td>
            <td>A non-user
Session, for snooping and user modeling</td>
          </tr>
          <tr>
            <td>WeakItemCollection</td>
            <td>A collection of
items based on Weak java references</td>
          </tr>
        </tbody>
      </table>
      <br />
      <img src="images/mic.jpg" alt="Input" />
      <h3><a name="DIG5" id="DIG5">Core Topic 5: Input</a></h3>
      <p>Almost
all user interaction with CoffeeMud begins and ends with the standard
command line parser. &nbsp;However, from time to time, it may be
important to prompt the player for further information, whether it be a
name for their new frog, a confirmation that they really want a frog as
a pet, or a set of one-letter options on what to do with the frog once
they have it. &nbsp;To accomplish this purpose, there are several
standard-issue methods on the Session object accessible from the player
MOB to allow you to do this, some are old and bad, and some are new and
better. &nbsp;Lets look at the old bad ones first, because it's
important to understand them to know why they are bad:</p>
      <pre>if(mob.session()!=null) <br />{<br />  String s=mob.session().prompt("Enter a message number (1): ","1");<br />  if ((s.length()&gt;0)&amp;&amp;(CMath.isInteger(s))) <br />  {<br />    if(mob.session().confirm("Are you sure you want to view message #"+s+" (Y/n)?","Y")) <br />    {<br />&nbsp;&nbsp;&nbsp;   mob.session().println("Here is message #"+s);<br />&nbsp;&nbsp;&nbsp;   // .... show them the message<br />      String choice=mob.session().choose("Would you like to D)elete or K)eep this message (d/K)?","DK","K");<br />      if(choice.equals("K")) <br />      {<br />        // .... delete the message<br />&nbsp;&nbsp;&nbsp;     mob.session().println("Message #"+s+" deleted.);<br />      }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;}<br />}<br /></pre>
      <p>In the above example, we
check to see if the <span style="font-family: monospace;">session()</span>
method on the MOB
object is non-null. &nbsp;This is important! All NPCs in your game
will
have a null-<span style="font-family: monospace;">session()</span>.
&nbsp;Only players, who are also the only ones capable of
responding to
prompts, have a non-null <span style="font-family: monospace;">session()</span>.
&nbsp; Next we <span style="font-family: monospace;">prompt(..)</span>
the user for a message number. &nbsp;The first parameter to this
method
is the prompt to display, while the second parameter is the default
response should the user just hit ENTER by itself. &nbsp;Next we
ask
the user to<span style="font-family: monospace;"> confirm(...) </span>that
they really want to view that message. &nbsp;The first parameter to <span
 style="font-family: monospace;">confirm(...)</span>
is again the message to display, while the second is either "Y" or "N",
meaning what the default is should the user just hit ENTER.
&nbsp;Last
we ask the user to <span style="font-family: monospace;">choose(...)</span>
from among 2 options for dealing with the message, where the first
parameter is again the message to display, the second parameter is a
string containing all the one-letter choices available to the user, and
the last parameter is the default should the user just hit ENTER.</p>
      <p>The
above example represents the way all prompting has been done in
CoffeeMud since 1.0. &nbsp;And it still works! However, it is a bad
idea to call those methods, and it's important to know why.
&nbsp;The
reason has to do with threads. A thread represents your computer's
opportunity to execute code in the computer; the more threads a program
has, the more things it can do at once. &nbsp;Everything in
CoffeeMud
runs in&nbsp;threads. &nbsp;However, threads are expensive to
have
around, and fewer of them is better than more. &nbsp;For this
reason,
almost everything in CoffeeMud shares threads with everything else,
which helps prevent the system from using too many or from running out
of them. &nbsp;Sharing is good; once a piece of CoffeeMud is
finished
running, it hands its thread off to other parts of CoffeeMud.
&nbsp;However, the three methods shown above ( <span
 style="font-family: monospace;">prompt(String,String)</span>, <span
 style="font-family: monospace;">confirm(String,String)</span>,
and <span style="font-family: monospace;">choose(String,
String, String)</span>
) do not share their thread with the rest of CoffeeMud. &nbsp;In
fact,
what happens when they execute is that the precious thread that is
running that piece of code just sits around doing nothing until the
user presses ENTER. &nbsp;This is *awful*. &nbsp;For this
reason, a new
method of prompting the user was added to the&nbsp;<span
 style="font-family: monospace;">session()</span>
object to allow your
Java to prompt the user without hogging the thread all to itself.
&nbsp;So, let's look at a new example:</p>
      <pre>final Session session=mob.session();<br />if(session != null) <br />{<br />  session.prompt(new InputCallback(InputCallback.Type.PROMPT,"1",0)<br />  {<br />    public void showPrompt() { session.printPrompt("Enter a message number (1): ");}<br />    public void timedOut() { }<br />    public void callBack() <br />    {<br />      if ((this.input.length()&gt;0)&amp;&amp;(CMath.isInteger(this.input))) <br />      {<br />        final String messageNumber=this.input;<br />        session.prompt(new InputCallback(InputCallback.Type.CONFIRM,"Y",0)<br />        {<br />          public void showPrompt() { session.printPrompt("Are you sure you want to view message #"+messageNumber+" (Y/n)?");}<br />          public void timedOut() { }<br />          public void callBack() <br />          {<br /> &nbsp;&nbsp;&nbsp;        session.println("Here is message #"+messageNumber);<br />&nbsp;&nbsp;&nbsp;         // .... show them the message<br />            session.prompt(new InputCallback(InputCallback.Type.CHOOSE,"K","DK",0)<br />            {<br />              public void showPrompt() { session.printPrompt("Would you like to D)elete or K)eep this message (d/K)?");}<br />              public void timedOut() { }<br />              public void callBack() <br />              {<br />                if(this.input.equals("K")) <br />                {<br />                  // .... delete the message<br /> &nbsp;&nbsp;&nbsp;              session.println("Message #"+messageNumber+" deleted.");<br />                }<br /> &nbsp;            }<br />            });<br />          }<br />        });<br />      }<br />    }<br />  });<br />}</pre>
      <p>The
above code does exactly what the first block of code did, but does it
without hogging any threads. &nbsp;It does it using a principle
called
"call backs", which you should look up online to learn more about.
&nbsp;In this case, the new <span style="font-family: monospace;">session.prompt(InputCallback)</span>
method is called with a customized inline java class of the abstract
InputCallback class. &nbsp;You'll notice that the InputCallback
constructor takes a InputCallback.Type as its first parameter, to tell
what type of prompt it is, then it takes a default value, just like the
old methods did, and he last parameter is a time, in milliseconds,
before the prompt will time-out (we use 0 to prevent timeouts).
&nbsp;The <span style="font-family: monospace;">InputCallback.Type.CHOOSE</span>
constructor also accepted, just before the timeout value, the letters
to choose from, just like in the old <span
 style="font-family: monospace;">session().choose(..)</span>
method.
&nbsp;In every case, the first thing that happens is that
the&nbsp;<span style="font-family: monospace;">InputCallback.showPrompt()&nbsp;</span>method
is called to display any necessary messages to the user.
&nbsp;Then,
the new <span style="font-family: monospace;">session.prompt(...)&nbsp;</span>immediately
returns, allowing any code afterwards to immediately execute.
&nbsp;However, the user must now enter something as well.
&nbsp;After
the user enters something valid, the <span
 style="font-family: monospace;">InputCallback.callBack()</span>
method
is called, and <span style="font-family: monospace;">this.input</span>
will contain the information the user entered. &nbsp;</p>
      <p>Two
things to bear in mind when working with these asynchronous user input
prompts: one, any variables that are local to the surrounding method
must either be final, or copied into final variables to be accessible
in the <span style="font-family: monospace;">callBack() </span>methods
below. &nbsp;Another thing is to always bear in mind that <span
 style="font-family: monospace;">session().prompt(InputCallback)</span>
displays a message and returns immediately -- it does not block the
thread like the other methods did. &nbsp;This last fact will play
with
your mind and mess up your coding if you aren't careful.</p>
      <img style="width: 87px; height: 80px;" alt="coffeedb"
 src="images/coffeedb.jpg" /><br />
      <h3><a name="DIG6" id="DIG5">Core Topic 6: Database
Tables</a></h3>
If all goes well, you will never ever have to care about this topic.
&nbsp;CoffeeMud includes numerous ways to expand the data storage
of its numerous objects without careing how or where it is being
persisted. &nbsp;However, for the curious or those who enjoy
danger, here is a description of the CoffeeMud Database Tables.<br />
      <br />
By way of <big><span style="font-weight: bold;">overview</span>,</big>
the CoffeeMud database schema reflects the sharp turns in design that
CoffeeMud has taken over the years. &nbsp;<br />
      <br />
Originally, CoffeeMud games were meant to be built by coders writing
Java objects. &nbsp;Since all the little details would be "stored"
in java class files, that left very little for the actual database to
persist. &nbsp;Mobs and Items in rooms would only have needed to
persist little details that might differ from instance to instance,
such as the simple Java Class name (what we still call the ID()),
&nbsp;level, rejuvination rate, a general numeric value (ability)
that each java class can use for its own purposes, as well as a general
string value (miscText) that they can use. &nbsp;The exception to
this would be the players themselves, which would have lots and lots of
database fields, since they would vary much more than mobs and items.<br />
      <br />
Later, CoffeeMud was changed to be built online at runtime.
&nbsp;Suddenly all the little details that were stored in Java had
to be persisted to the database. &nbsp;This was
accomplished&nbsp; by storing all of those details as an XML
document in the same place that the general string value (miscText)
was.&nbsp;Still, this left the system with relatively few tables
with relatively few fields. &nbsp;The fact that all that XML data
could not be queried was fairly unimportant.
&nbsp;&nbsp;CoffeeMud loaded all of its data at boot-time, so
that even the tables and relations, such as they were, were mostly
unused after the boot completed.<br />
      <br />
For a long time, things stayed this way.&nbsp;&nbsp;However,
the day came when suddenly queries became important.
&nbsp;Journals, forums, virtual filesystems, polls, "thin" areas,
and backlogs all required the data to be pulled in on demand.
&nbsp;The number of tables as well as the fields in existing tables
began to modestly expand. &nbsp;Eventually the weight of new
features whose data fit nowhere else caused the numer of tables to
balloon to the current list.<br />
      <br />
All the while, CoffeeMud tried to maintain compatibility, not only with
fakedb, but with every other database, commercial or open source.
&nbsp;Every database engine has its own standard table names,
special column names, and so forth. &nbsp;Predicting when one
column name would conflict with which database engine was a problem
from the very start. &nbsp;Therefore, the database tables and colum
names were given almost cryptic names in order to help eliminate the
possibility of conflict. &nbsp;<br />
      <br />
And that, my friends, is why the CoffeeMud database is the way it is.
&nbsp;So, how is it? &nbsp;Let's look:<br />
      <br />
      <table
 style="text-align: left; background-color: rgb(255, 255, 204); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%"><big>cmvfs</big></td>
            <td>The Virtual
(Database) File System storage. &nbsp;One row per file.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmchab</big></td>
            <td>Per-character
reference for Abilities, and later Scripts, Effects and characterr
Behaviors as well. &nbsp;One Char Ability per row.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmchcl</big></td>
            <td>Per-character
reference for Clan membership and Role. One Char Clan Membership per
row.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmstat</big></td>
            <td>Per-time-period
(usually 1 day) collection of game statistics, for the STAT command and
MUDGrinder game stats. &nbsp;One row per period.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmpoll</big></td>
            <td>The polls given to
users at login. &nbsp;One Poll and their results per row.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmchar</big></td>
            <td>The main Character
table. &nbsp;One row per Character.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmchfo</big></td>
            <td>Per-character
followers table for the mobs following players around. &nbsp;One
row per Char&nbsp;Follower.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmchit</big></td>
            <td>Per-character
inventory table for the items mobs carry around and wear. &nbsp;One
row per Char Item.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmroch</big></td>
            <td>Per-room mob
table, for the mobs that start in each room. &nbsp;One row per Room
MOB.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmroex</big></td>
            <td>Per-room exit
table, for the exit objects from each room. &nbsp;One row per Room
Exit.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmroit</big></td>
            <td>Per-room item
object table, for the items sitting in each room. &nbsp;One row per
Room Item.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmroom</big></td>
            <td>The main Room
table. &nbsp;One row per Room. &nbsp;Also holds the entire
catalog in special room ids.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmquests</big></td>
            <td>Quests table.
&nbsp;One row per quest definition string, which can be a whole
quest script or a reference to an external file.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmarea</big></td>
            <td>The Areas table.
&nbsp;One row per Area.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmjrnl</big></td>
            <td>The Journals
table, which is also for Forums, Command Journals, and Email.
&nbsp;One row per forum message.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmclan</big></td>
            <td>Clan table.
&nbsp;One row per Clan.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmpdat</big></td>
            <td>Originally Player
Data, with one row per Player Section Key of data. &nbsp;Think bank
accounts. &nbsp;Also holds clan data as well.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmgrac</big></td>
            <td>Generic Race
table. &nbsp;One row per Race.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmccac</big></td>
            <td>Generic Character
Class table. &nbsp;One row per Class.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmgaac</big></td>
            <td>Generic Ability
table. &nbsp;One row per Ability.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmacct</big></td>
            <td>Common Account
table, if you use that optional system. &nbsp;One row per player
account.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmbklg</big></td>
            <td>Channels Backlog
table. &nbsp;One row per Channel message.</td>
          </tr>
          <tr>
            <td style="font-weight: bold;"><big>cmclit</big></td>
            <td>Clan Item table,
for each clan item deposited in various areas. &nbsp;One row per
room clan item.</td>
          </tr>
        </tbody>
      </table>
      <br />
      <p style="font-weight: bold; font-style: italic;"><big>CMCHAB</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMUSERID</td>
            <td width="35%">Character name</td>
            <td style="font-weight: bold;" width="15%">CMABID</td>
            <td>Ability ID / Behavior ID / Effect ID</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMABPF</td>
            <td width="35%">Proficiency (MIN=script/behavior,
MAX=effect)</td>
            <td style="font-weight: bold;" width="15%">CMABTX</td>
            <td width="35%">Misc Text</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMCHAR</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCHID</td>
            <td width="35%">MOB class ID</td>
            <td style="font-weight: bold;" width="15%">CMUSERID</td>
            <td width="35%">Character name</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMPASS</td>
            <td width="35%">Password (encoded / hash)</td>
            <td style="font-weight: bold;" width="15%">CMCLAS</td>
            <td width="35%">Char Class(es), ; delimited </td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMSTRE</td>
            <td width="35%">Base Strength</td>
            <td style="font-weight: bold;" width="15%">CMRACE</td>
            <td width="35%">Race ID</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDEXT</td>
            <td width="35%">Base Dexterity</td>
            <td style="font-weight: bold;" width="15%">CMCONS</td>
            <td width="35%">Base Constitution</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMGEND</td>
            <td width="35%">Gender</td>
            <td style="font-weight: bold;" width="15%">CMWISD</td>
            <td width="35%">Base Wisdom</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMINTE</td>
            <td width="35%">Base Intelligence</td>
            <td style="font-weight: bold;" width="15%">CMCHAR</td>
            <td width="35%">Base Charisma</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMHITP</td>
            <td width="35%">Base Hit Points</td>
            <td style="font-weight: bold;" width="15%">CMLEVL</td>
            <td width="35%">Class Level(s), ; delimited</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMMANA</td>
            <td width="35%">Base Mana</td>
            <td style="font-weight: bold;" width="15%">CMMOVE</td>
            <td width="35%">Base Movement</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDESC</td>
            <td width="35%">Description</td>
            <td style="font-weight: bold;" width="15%">CMALIG</td>
            <td width="35%">(Unused -- replaced with Faction system)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMEXPE</td>
            <td width="35%">Experience Points</td>
            <td style="font-weight: bold;" width="15%">CMEXLV</td>
            <td width="35%">Experience to next level</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMWORS</td>
            <td width="35%">Deity name</td>
            <td style="font-weight: bold;" width="15%">CMPRAC</td>
            <td width="35%">Practice Points</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMTRAI</td>
            <td width="35%">Training Points</td>
            <td style="font-weight: bold;" width="15%">CMAGEH</td>
            <td width="35%">Age in Hours</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMGOLD</td>
            <td width="35%">Money, deprecated for Coin items</td>
            <td style="font-weight: bold;" width="15%">CMWIMP</td>
            <td width="35%">Wimp Hit Point Level</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMQUES</td>
            <td width="35%">Quest Points</td>
            <td style="font-weight: bold;" width="15%">CMROID</td>
            <td width="35%">Current Room ID || Starting Room ID</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDATE</td>
            <td width="35%">Last login Date/Time</td>
            <td style="font-weight: bold;" width="15%">CMCHAN</td>
            <td width="35%">Channels on/off bitmask</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMATTA</td>
            <td width="35%">Base Attack</td>
            <td style="font-weight: bold;" width="15%">CMAMOR</td>
            <td width="35%">Base Armor</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDAMG</td>
            <td width="35%">Base Damage</td>
            <td style="font-weight: bold;" width="15%">CMBTMP</td>
            <td width="35%">MOB Attributes Bitmap (ansi, mxp, etc..)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMLEIG</td>
            <td width="35%">Leige/Lord Name</td>
            <td style="font-weight: bold;" width="15%">CMHEIT</td>
            <td width="35%">Height</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMWEIT</td>
            <td width="35%">Base Weight</td>
            <td style="font-weight: bold;" width="15%">CMPRPT</td>
            <td width="35%">Prompt String (if custom)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCOLR</td>
            <td width="35%">Custom Color strings</td>
            <td style="font-weight: bold;" width="15%">CMLSIP</td>
            <td width="35%">Last login IP address</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMEMAL</td>
            <td width="35%">Email Address</td>
            <td style="font-weight: bold;" width="15%">CMPFIL</td>
            <td width="35%">All Player Stats as XML document</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMSAVE</td>
            <td width="35%">Saving Throws stats ; delimited</td>
            <td style="font-weight: bold;" width="15%">CMMXML</td>
            <td width="35%">All Factions and their values as XML
document</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMCHFO</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMUSERID</td>
            <td width="35%">Character name</td>
            <td style="font-weight: bold;" width="15%">CMFONM</td>
            <td width="35%">Follower key (unique per char
&nbsp;follower id)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMFOID</td>
            <td width="35%">MOB class ID for the follower</td>
            <td style="font-weight: bold;" width="15%">CMFOTX</td>
            <td width="35%">Misc Text / GenMob XML</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMFOLV</td>
            <td width="35%">Level</td>
            <td style="font-weight: bold;" width="15%">CMFOAB</td>
            <td width="35%">Misc number / Ability</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMCHCL</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMUSERID</td>
            <td width="35%">Character name</td>
            <td style="font-weight: bold;" width="15%">CMCLAN</td>
            <td width="35%">Clan name</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCLRO</td>
            <td width="35%">Characters Role in the Clan</td>
            <td style="font-weight: bold;" width="15%">CMCLSTS</td>
            <td width="35%">Character Clan Stats (kills, pvps, etc)</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMCHIT</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMUSERID</td>
            <td width="35%">Character name</td>
            <td style="font-weight: bold;" width="15%">CMITNM</td>
            <td width="35%">Character item key (unique per char item)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITID</td>
            <td width="35%">Item class ID</td>
            <td style="font-weight: bold;" width="15%">CMITTX</td>
            <td width="35%">Misc Text / GenItem XML</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITLO</td>
            <td width="35%">Container item key (matches CMITNM)</td>
            <td style="font-weight: bold;" width="15%">CMITWO</td>
            <td width="35%">Worn code (if the item is being worn)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITUR</td>
            <td width="35%">Uses remaining / Item condition</td>
            <td style="font-weight: bold;" width="15%">CMITLV</td>
            <td width="35%">Level</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITAB</td>
            <td width="35%">Misc number / Ability</td>
            <td style="font-weight: bold;" width="15%">CMHEIT</td>
            <td width="35%">Height (armor "size")</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMROCH</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMROID</td>
            <td width="35%">Room ID</td>
            <td style="font-weight: bold;" width="15%">CMCHNM</td>
            <td width="35%">Room mob key (unique per room mob)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCHID</td>
            <td width="35%">MOB class ID</td>
            <td style="font-weight: bold;" width="15%">CMCHTX</td>
            <td width="35%">Misc Text / GenMOB XML</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCHLV</td>
            <td width="35%">Level</td>
            <td style="font-weight: bold;" width="15%">CMCHAB</td>
            <td width="35%">Misc number / Ability</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCHRE</td>
            <td width="35%">Rejuvination (Rejuv) ticks</td>
            <td style="font-weight: bold;" width="15%">CMCHRI</td>
            <td width="35%">Riding key (matched CMITNM or CMCHNM)</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMROEX</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMROID</td>
            <td width="35%">Room ID</td>
            <td style="font-weight: bold;" width="15%">CMDIRE</td>
            <td width="35%">Direction code</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMEXID</td>
            <td width="35%">Exit class ID</td>
            <td style="font-weight: bold;" width="15%">CMEXTX</td>
            <td width="35%">Misc Text / GenExit XML</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMNRID</td>
            <td colspan="3" width="85%">Next Room ID (the one that this
exit travels to from CMROID)</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMROIT</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMROID</td>
            <td width="35%">Room ID</td>
            <td style="font-weight: bold;" width="15%">CMITNM</td>
            <td width="35%">Character item key (unique per room item)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITID</td>
            <td width="35%">Item class ID</td>
            <td style="font-weight: bold;" width="15%">CMITLO</td>
            <td width="35%">Container item key (matches CMITNM)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITTX</td>
            <td width="35%">Misc Text / GenItem XML</td>
            <td style="font-weight: bold;" width="15%">CMITRE</td>
            <td width="35%">Rejuvination (Rejuv) ticks</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITUR</td>
            <td width="35%">Uses remaining / Item condition</td>
            <td style="font-weight: bold;" width="15%">CMITLV</td>
            <td width="35%">Level</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITAB</td>
            <td width="35%">Misc number / Ability</td>
            <td style="font-weight: bold;" width="15%">CMHEIT</td>
            <td width="35%">Height (armor "size")</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMROOM</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMROID</td>
            <td width="35%">Room ID</td>
            <td style="font-weight: bold;" width="15%">CMLOID</td>
            <td width="35%">Room class ID</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMAREA</td>
            <td width="35%">Area name</td>
            <td style="font-weight: bold;" width="15%">CMDESC1</td>
            <td width="35%">Room title</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDESC2</td>
            <td width="35%">Room long description text</td>
            <td style="font-weight: bold;" width="15%">CMROTX</td>
            <td width="35%">Room properties (behaviors, effects, etc)
in XML</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMAREA</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMAREA</td>
            <td width="35%">Area name</td>
            <td style="font-weight: bold;" width="15%">CMTYPE</td>
            <td width="35%">Area class ID</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCLIM</td>
            <td width="35%">Climate code</td>
            <td style="font-weight: bold;" width="15%">CMSUBS</td>
            <td width="35%">SubOp character names, semicolon delimited</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDESC</td>
            <td width="35%">Long description</td>
            <td style="font-weight: bold;" width="15%">CMROTX</td>
            <td width="35%">Area properties (behaviors, effects, etc)
in XML</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMTECH</td>
            <td colspan="3" width="85%">Area theme code</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMJRNL</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMJKEY</td>
            <td width="35%">Journal Message Key (unique per message)</td>
            <td style="font-weight: bold;" width="15%">CMJRNL</td>
            <td width="35%">Journal name</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMFROM</td>
            <td width="35%">Message sender</td>
            <td style="font-weight: bold;" width="15%">CMDATE</td>
            <td width="35%">Message post date / time</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMTONM</td>
            <td width="35%">Message receiver / ALL</td>
            <td style="font-weight: bold;" width="15%">CMSUBJ</td>
            <td width="35%">Subject</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMPART</td>
            <td width="35%">Parent message (if this is a reply / child
message)</td>
            <td style="font-weight: bold;" width="15%">CMATTR</td>
            <td width="35%">Attributes (protected, etc..)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDATA</td>
            <td width="35%">Usually the journal name, not sure</td>
            <td style="font-weight: bold;" width="15%">CMUPTM</td>
            <td width="35%">Last updated date / time</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMIMGP</td>
            <td width="35%">Message image path</td>
            <td style="font-weight: bold;" width="15%">CMVIEW</td>
            <td width="35%">Number of message views</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMREPL</td>
            <td width="35%">Number of message replies / children</td>
            <td style="font-weight: bold;" width="15%">CMMSGT</td>
            <td width="35%">Message text</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMCLAN</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCLID</td>
            <td width="35%">Clan name</td>
            <td style="font-weight: bold;" width="15%">CMTYPE</td>
            <td width="35%">Unused, clan "type" code</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDESC</td>
            <td width="35%">Clan Description / Premise</td>
            <td style="font-weight: bold;" width="15%">CMACPT</td>
            <td width="35%">Acceptance settings for application (Zapper
Mask)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMPOLI</td>
            <td width="35%">Clan details (govt, relations, etc) as XML
doc</td>
            <td style="font-weight: bold;" width="15%">CMRCLL</td>
            <td width="35%">Clan recall room ID</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDNAT</td>
            <td width="35%">Clan donation room ID</td>
            <td style="font-weight: bold;" width="15%">CMSTAT</td>
            <td width="35%">Clan status code (active or not, etc)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMMORG</td>
            <td width="35%">Clan morgue room ID</td>
            <td style="font-weight: bold;" width="15%">CMTROP</td>
            <td width="35%">Clan trophies bitmask</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMCLIT</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCLID</td>
            <td width="35%">Clan name</td>
            <td style="font-weight: bold;" width="15%">CMITNM</td>
            <td width="35%">Character item key (unique per char item)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITID</td>
            <td width="35%">Item class ID</td>
            <td style="font-weight: bold;" width="15%">CMITTX</td>
            <td width="35%">Misc Text / GenItem XML</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITLO</td>
            <td width="35%">Container item key (matches CMITNM)</td>
            <td style="font-weight: bold;" width="15%">CMITWO</td>
            <td width="35%">Worn code (if the item is being worn)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITUR</td>
            <td width="35%">Uses remaining / Item condition</td>
            <td style="font-weight: bold;" width="15%">CMITLV</td>
            <td width="35%">Level</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMITAB</td>
            <td width="35%">Misc number / Ability</td>
            <td style="font-weight: bold;" width="15%">CMHEIT</td>
            <td width="35%">Height (armor "size")</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMQUESTS</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMQUESID</td>
            <td width="35%">Quest name (unique)</td>
            <td style="font-weight: bold;" width="15%">CMQUTYPE</td>
            <td width="35%">Quest class ID</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMQFLAGS</td>
            <td width="35%">Quest statue flags (suspended, etc)</td>
            <td style="font-weight: bold;" width="15%">CMQSCRPT</td>
            <td width="35%">Quest script, or load command</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMQWINNS</td>
            <td colspan="3" width="85%">List of Character name quest
winners (semicolon delimited)</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMPDAT</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMPLID</td>
            <td width="35%">Character name (or Clan name)</td>
            <td style="font-weight: bold;" width="15%">CMSECT</td>
            <td width="35%">Data "Section" (bank chain, for example)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMPKEY</td>
            <td width="35%">Data row key (unique per row)</td>
            <td style="font-weight: bold;" width="15%">CMPDAT</td>
            <td width="35%">Data as an XML document (usually)</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMGRAC</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMRCID</td>
            <td width="35%">Race ID</td>
            <td style="font-weight: bold;" width="15%">CMRDAT</td>
            <td width="35%">Race definition data XML</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMCCAC</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCCID</td>
            <td width="35%">Character Class ID</td>
            <td style="font-weight: bold;" width="15%">CMCDAT</td>
            <td width="35%">Character Class definition data XML</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMGAAC</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMGAID</td>
            <td width="35%">Ability ID</td>
            <td style="font-weight: bold;" width="15%">CMGAAT</td>
            <td width="35%">Ability definition data XML</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMGACL</td>
            <td colspan="3" width="85%">Generic Ability Class ID</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMSTAT</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMSTRT</td>
            <td width="35%">Start of data date/time</td>
            <td style="font-weight: bold;" width="15%">CMENDT</td>
            <td width="35%">End of data date/time</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDATA</td>
            <td colspan="3" width="85%">All the data stats for this
period as an XML document</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMPOLL</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMNAME</td>
            <td width="35%">Poll name (unique)</td>
            <td style="font-weight: bold;" width="15%">CMBYNM</td>
            <td width="35%">Poll creator / owner character name</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMSUBJ</td>
            <td width="35%">Subject</td>
            <td style="font-weight: bold;" width="15%">CMDESC</td>
            <td width="35%">Poll description / introduction</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMOPTN</td>
            <td width="35%">Options / selections as XML doc</td>
            <td style="font-weight: bold;" width="15%">CMFLAG</td>
            <td width="35%">Poll flags / status bitmask</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMQUAL</td>
            <td width="35%">Participant qualification zapper mask</td>
            <td style="font-weight: bold;" width="15%">CMRESL</td>
            <td width="35%">Results / Answers XML document</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMEXPI</td>
            <td colspan="3" width="85%">Poll expiration / end date time</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMVFS</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMFNAM</td>
            <td width="35%">File path and name, unique per row</td>
            <td style="font-weight: bold;" width="15%">CMDTYP</td>
            <td width="35%">File attributes bitmap (hidden, etc)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMMODD</td>
            <td width="35%">File modified date/time </td>
            <td style="font-weight: bold;" width="15%">CMWHOM</td>
            <td width="35%">Owner character name</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDATA</td>
            <td colspan="3" width="85%">File data, B64 encoded</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMACCT</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMANAM</td>
            <td width="35%">Account name (unique)</td>
            <td style="font-weight: bold;" width="15%">CMPASS</td>
            <td width="35%">Account password (encrypted / hash)</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMCHRS</td>
            <td width="35%">Account characters list, semicolon delimited</td>
            <td style="font-weight: bold;" width="15%">CMAXML</td>
            <td width="35%">Account details as XML document</td>
          </tr>
        </tbody>
      </table>
      <p style="font-weight: bold; font-style: italic;"><big>CMBKLG</big></p>
      <table
 style="text-align: left; background-color: rgb(204, 255, 255); width: 100%;"
 border="1" cellpadding="2" cellspacing="2">
        <tbody>
          <tr>
            <td style="font-weight: bold;" width="15%">CMNAME</td>
            <td width="35%">Channel name</td>
            <td style="font-weight: bold;" width="15%">CMINDX</td>
            <td width="35%">Backlog message index number</td>
          </tr>
          <tr>
            <td style="font-weight: bold;" width="15%">CMDATE</td>
            <td width="35%">Backlog message date/time</td>
            <td style="font-weight: bold;" width="15%">CMDATA</td>
            <td width="35%">CMMsg data, comma delimited</td>
          </tr>
        </tbody>
      </table>
      <br />
      <br />
&nbsp;<img src="images/pencil.jpg" alt="commands" />
      <h2><a name="CMDS" id="CMDS">Commands</a></h2>
      <p>Commands are exactly what
they sound like: LOOK, QUIT, KILL,
GET, and all the other things you type into the mud are handled by
CoffeeMud Commands.</p>
      <p>A Custom Command may or
may not belong to any particular
package, though it is important that the <code>ID()</code>
of the Command be unique in the system. A custom Command imports the
same packages mentioned in the first section of this document under
Complete Default Import List as well as
com.planet_ink.coffee_mud.Commands.StdCommand.</p>
      <pre>public class DoNothing extends com.planet_ink.coffee_mud.Commands.StdCommand<br />{<br /> public DoNothing(){}<br /><br /> private final String[] access={ "DONOTHING" };<br /> public String[] getAccessWords(){ return access; }<br /></pre>
      <p>All Commands should
extend StdCommand for conformity's sake,
though it is not required so long as your class implements the
com.planet_ink.coffee_mud.core.interfaces.Command interface. In our
example above, we have an empty constructor, but we do define some
access words.</p>
      <p>Access words are what you
think they are: the words which,
when typed, allow the users to activate the command. We define a string
array containing one such access word in this case, and then define our
Command interface method getAccessWords() to return that array. Our
String array may contain as many strings as you would need to provide
sufficient words to activate this command.</p>
      <pre>public double actionsCost(MOB mob, List&lt;String&gt; cmds){ return 1.0; }<br />public double combatActionsCost(MOB mob, List&lt;String&gt; cmds){ return 1.0; }<br /><br />public boolean canBeOrdered(){ return true; }<br /></pre>
      <p>The next two methods, <code>actionsCost()</code>
and <code>combatActionsCost()</code>,
designate how LONG it takes to execute this command. A value of 0 means
that the command always happens instantly. A value greater than 0 will
always take that many free actions to complete. A standard player may
perform 1 action in a given Tick ( 4 second period), or 2 actions
during combat
in the default combat system -- they retain their 1 action per tick in
other combat systems). Action costs may be partial as well, costing 0.5
(1/2 action) or other values.</p>
      <p>The <code>canBeOrdered()</code>
method designates whether
this
command represents an action which a creature or player might
reasonably be ordered to do by another player. Archons and those with
the "ORDER" security code are exempt from this flag.</p>
      <pre> public boolean securityCheck( MOB mob )<br /> {<br />   return CMSecurity.isAllowed( mob, mob.location(), CMSecurity.SecFlag.IMMORT);<br /> }<br /></pre>
      <p>And speaking of security,
this method returns whether or not
the given mob may even have access to this command. If the <code>securityCheck()</code>
method returns false, the command and its access words will behave as
if they do not even exist, returning "Huh?" should a player attempt to
use it. Returning true, however, means only that the execute method
below may be accessed. Any further security would have to be
implemented during execution of the command.</p>
      <p>In the above example, we
call the <code>isAllowed()</code>
method in CMSecurity with the mob reference, the room in which the mob
is located, and the security code CMSecurity.SecFlag.IMMORT. This asks
the Security
module whether this mob, at this location, is authorized to perform
functions designated by the "IMMORT" security code.</p>
      <pre> public boolean preExecute(MOB mob, List&lt;String&gt; commands, int metaFlags, int secondsElapsed, double actionsRemaining)<br /> throws java.io.IOException;<br /> {<br />   if( secondsElapsed == 0 )<br />   {<br />     mob.tell( "You are preparing to do nothing." );<br />   }<br /><br />   if( secondsElapsed == 3 )<br />   {<br />     mob.tell( "You almost ready to do nothing." );<br />   }<br /> }<br /></pre>
      <p>The <code>preExecute()</code>
method is very rarely
implemented, but it is important to mention in light of the <code>actionsCost()</code>
and <code>combatActionsCost()</code>
values above. The purpose of the method is to give the player or the
room status messages when the player does not yet have enough actions
to execute the command. The method will be called immediately if a
player does not have enough actions to execute the command, and will
present a secondsElapsed value of 0. It will then be called again every
second or so with updated values until the player has enough actions to
proceed.</p>
      <pre> public boolean execute( MOB mob, List&lt;String&gt; commands, int metaFlags )<br /> throws java.io.IOException<br /> {<br />   String parameters = CMParms.combine( commands, 1 );<br />   if( parameters.length() == 0 )<br />   {<br />     mob.tell( "Nothing done." );<br />   }<br />   else<br />   {<br />     mob.tell( "Nothing, not even '" + parameters + "', done." );<br />   }<br />   return false;<br /> }<br /> <br /></pre>
      <p>Our last method is where
the command actually does its work.
The mob given would be the MOB object trying to execute this command,
while commands is a List of parameters.</p>
      <p>The parameter commands is
never null, and by convention is a
List of strings starting with the access word used to execute the
command. For instance, if the user entered:</p>
      <pre>donothing never "and always" never<br /></pre>
      <p>The commands List would
be size 4, and contain "donothing",
"never", "and always", and "never" respectively. In the case of this
command, we use one of the String utilities to recombine the last 3
parameters back into one string "never and always never", and then
issue a message to the mob depending upon whether there were any
parameters at all. Since this command requires a command word to access
it, it is reasonable to assume that the 0th element in the commands
List is the word "donothing", which means we can safely ignore it.</p>
      <img src="images/smurf.jpg" alt="MOBs" />
      <h2><a name="MOBS" id="MOBS">MOBs</a></h2>
      <p>MOBs, or "Moveable
OBjects", are the creatures and characters
which the players fight. In CoffeeMud, they are among the simpler
objects to code. This is not because they are uncomplex. In fact, they
are MOST complex. However, this complexity comes due to the myriad of
Items, Behaviors, Properties, and Abilities that are added to them.
Short of these numerous additions, a MOB by himself is rather simple!</p>
      <p>This simplicity is
important however, and should be carefully
considered before you run off to create new MOBs. If you are creating a
new MOB because you want a creature to have some new kind of ability,
then are you sure it is not a new Ability you want to write? If the new
MOBs behavior is complex and unique, are you sure it's not a new
Behavior you wish to code? Otherwise, the best reasons to be coding
MOBs are actually three: because you have a particular kind of monster
that is used prolifically in your world, and you want to save memory by
coding him as a special mob that extends StdMOB, or because you want to
code special player capabilities by creating your own class that both
extends StdMOB and has an <code>ID()</code>
of "StdMOB", or because
you want to add special NPC monster capabilities by creating your own
class that extends GenMob and has an <code>ID()</code>
of "GenMob".</p>
      <p>So, if you are sure this
is what you want to do, carry on! The
directory for your custom coded MOB objects should be specified using
the "MOBS" entry in the coffeemud.ini file. See the section above on
Rebuilding CoffeeMud for more information on this feature.</p>
      <h3><a name="mobcoding" id="mobcoding">Coding a new
MOB</a></h3>
      <p>A Custom MOB may or may
not belong to any particular package,
though it is important that the ID() of the MOB be unique in the
system. A custom MOB imports the same packages mentioned in the first
section of this document under Complete Default Import List as well as
(in this case) com.planet_ink.coffee_mud.MOBS.StdMOB because our sample
mob extends it.</p>
      <p>A MOB class must extend
either StdMOB or GenMob, StdShopKeeper
or GenShopKeeper, StdRideable or GenRideable depending on the basic
capabilities, and customizability you would like. Although Generic
objects are more customizable at run-time, they also take a long time
for the system to load and build, and take up a lot of database disk
space, and more memory. For this reason, using Standard instead of
Generic wherever possible is always good. Another reason for extending
StdMOB is because all players in the game use the "StdMOB" class as a
basis, which means that special player fields and capabilities can be
coded by both extending the StdMOB class, and also giving your custom
class an <code>ID()</code>
of "StdMOB". If you do this, however, make
sure your class is loaded after the %DEFAULT% list in your
coffeemud.ini file.</p>
      <p>As was stated, each
unique MOB must also have a custom <code>ID()</code>
method as shown below. Notice that the <code>ID()</code>
is the same
as the name of the class. This is no accident -- this is required!</p>
      <pre>public class MyNewMOB extends com.planet_ink.coffee_mud.MOBS.StdMOB<br />{<br />  public String ID(){ return "MyNewMOB";}<br /></pre>
      <p>All of your customizing
will be done inside the constructor:
name, displayText, description, etc, etc.</p>
      <pre>  public MyNewMOB()<br />  {<br />     super();<br /><br />     setName( "a new mob" );<br />     setDescription( "It`s furry with 2 legs" );<br />     setDisplayText( "My new mob is standing here." );<br /><br />     CMLib.factions().setAlignment( this, Faction.Align.NEUTRAL );<br />     setMoney( 0 );<br />     setWimpHitPoint( 2 );<br />     basePhyStats().setDamage( 4 );<br /><br />     basePhyStats().setAbility( 0 );<br />     basePhyStats().setLevel( 1 );<br />     basePhyStats().setArmor( 30 );<br />     basePhyStats().setSpeed( 1.0 );<br />     basePhyStats().setAttackAdjustment( 30 );<br />     basePhyStats().setWeight( 85 );<br />     basePhyStats().setSensesMask( PhyStats.CAN_SEE_DARK|PhyStats.CAN_SEE_INFRARED );<br />     basePhyStats().setDisposition( PhyStats.IS_FLYING );<br />     baseCharStats().setCurrentClass( CMClass.getCharClass( "Fighter" ) );<br /><br />     baseCharStats().setMyRace( CMClass.getRace( "Dog" ) );<br />     baseCharStats().getMyRace().startRacing( this, false );<br />     baseCharStats().setStat( CharStats.STAT_GENDER, (int)'F' );<br />     baseCharStats().setStat( CharStats.STAT_STRENGTH, 18 );<br />     baseCharStats().setStat( CharStats.STAT_INTELLIGENCE, 14 );<br />     baseCharStats().setStat( CharStats.STAT_WISDOM, 13 );<br />     baseCharStats().setStat( CharStats.STAT_DEXTERITY, 15 );<br />     baseCharStats().setStat( CharStats.STAT_CONSTITUTION, 12 );<br />     baseCharStats().setStat( CharStats.STAT_CHARISMA, 13 );<br />     baseCharStats().setStat( CharStats.STAT_SAVE_COLD, 50 );<br /><br />     baseState.setHitPoints( CMLib.dice().roll( basePhyStats().level(), 20, 20 ) );<br />     baseState.setMana( CMLib.dice().roll( basePhyStats().level(), 50, 100 ) );<br /><br />     recoverMaxState();<br />     resetToMaxState();<br />     recoverPhyStats();<br />     recoverCharStats();<br />  }<br /></pre>
      <p>You can see here that the
basic stats have been filled out,
from level to attack speed, alignment and weight. For numeric values,
higher is always better, except for Armor, which is always best low,
and comes down from 100. You'll notice above that two commands are
required to set the Race of the creature. Also, you should realize that
the numerous saving throws, and senses as well as dispositions
(sneaking, hiding) are not represented above, but can easily be added
using the format shown.</p>
      <p>It is very important to
note the last four commands. These
commands "reset" the MOB, and "implement" the scores which are given in
the several areas. <code>recoverPhyStats()</code>,
for instance, must
be called whenever a change is made to the <code>basePhyStats()</code>
object. Ditto for "CharStats" and "MaxState".</p>
      <p>Now, suppose we wanted to
add an Effect or Behavior or Ability
to your MOB. The proper place for such a statement would be in the same
above constructor, among the other commands. Preferably before the
several "recover" commands, but after the several stat definitions. Of
course, all of this is unnecessary for a new GenMOB object.</p>
      <pre>  addNonUninvokableEffect( CMClass.getAbility( "Fighter_Berzerk" ) );<br /><br />  Ability A = CMClass.getAbility( "Prop_Resistance" );<br />  if( A != null )<br />  {<br />     A.setMiscText( "Fire 200%" );<br />     addNonUninvokableEffect( A );<br />  }<br /><br />  addAbility( CMClass.getAbility( "Poison" ) );<br /><br />  addBehavior( CMClass.getBehavior( "MudChat" ) );<br />  addBehavior( CMClass.getBehavior( "Mobile" ) );<br />  addBehavior( CMClass.getBehavior( "CombatAbilities" ) );<br /></pre>
      <p>The commands above will
make the MOB permanently Berzerk,
gives it the ability to Poison folks while in combat, allows the MOB to
Chat with other players, and to walk around in its area. The last
behavior gives the MOB the wisdom to use its Poison ability while in
combat.</p>
      <p>If your MOB extends
StdShopKeeper, you will need to add your
inventory manually through the <code>getShop()</code>
object access
method as shown below. The <code>getShop()</code>
method returns an instance of the
com.planet_ink.coffee_mud.Common.interfaces.CoffeeShop interface, which
stores inventory for the shopkeepers. In creating the shopkeepers, you
will also need to specify the type of ShopKeeper.</p>
      <pre>  setWhatIsSold( ShopKeeper.ONLYBASEINVENTORY );<br /><br />  Weapon sword = (Weapon)CMClass.getWeapon( "Longsword" );<br />  getShop().addStoreInventory( sword, 35, -1, this );<br />  Armor mail = (Armor)CMClass.getArmor( "FullPlate" );<br />  getShop().addStoreInventory( mail, 35, -1, this );<br />  Item waterskin = CMClass.getItem( "Waterskin" );<br />  getShop().addStoreInventory( waterskin, 35, -1, this );<br /></pre>
      <p>You'll recall from the
Archon's Guide that there are many
different types of ShopKeepers, including trainers, pet sellers,
weaponsmiths, and others.</p>
      <p>StdRideable MOBs will
require a few other settings as well!</p>
      <pre>  setRideBasis( Rideable.RIDEABLE_LAND );<br />  setMobCapacity( 2 );<br /></pre>
      <p>The last thing is to give
the MOB equipment, armor, and
weapons. The following commands will do the trick!</p>
      <pre>  Weapon sword = (Weapon)CMClass.getWeapon( "Longsword" );<br />  addItem( sword );<br />  sword.wearIfPossible( this );<br /><br />  Armor mail = (Armor)CMClass.getArmor( "FullPlate" );<br />  addItem( mail );<br />  mail.wearIfPossible( this );<br /><br />  Item sack = (Item)CMClass.getItem( "StdContainer" );<br />  addItem( sack );<br /><br />  Item waterskin = (Item)CMClass.getItem( "Waterskin" );<br />  addItem( waterskin );<br />  waterskin.setContainer( sack );<br /></pre>
      <p>And that's all there is
to creating a new standard MOB. Easy,
huh? Well, obviously, the real complexity of MOBs comes when the
Behaviors and Abilities are programmed, but that is not covered here,
of course.</p>
      <p>There is also the
advanced topic of extending the capabilities
of the existing MOB classes. As mentioned previously, this consists in
creating your own java classes with the same class name and <code>ID()</code>
string methods as the base CoffeeMud MOB classes, and the adding the
reference to your custom class to the coffeemud.ini file's MOBS enter
after the %DEFAULT% entry. Now, adding or extending the capabilities of
these classes typically means both adding your own methods, and
extending the importing existing methods in those classes. The most
important of those existing methods are discussed above in the Core
Topics, namely okMessage, executeMsg, and tick. However, there are many
other methods which might be extended to the end of altering or
enhancing basic aspects of the mud. Those are numerated both in the
classes you are extending, and in
com.planet_ink.coffee_mud.MOBS.interfaces.MOB.java. Consult the
CoffeeMud java docs for more information.</p>
      <h3><a name="moblife" id="moblife">Bringing MOBs to
Life, and
Taking That Life Away</a></h3>
      <p>The following
instructions are supplemental, and unnecessary.
Once you have created your new MOB, modified your INI file, and
rebooted your CoffeeMud server, you need only use the CREATE and other
Archon commands to make use of him. If, for some reason, you want to
know HOW these commands do their work, however, here it is.</p>
      <p>To bring a MOB into
existence, a MOB must have somewhere to
exist! Presumably, this is some room on your map. Rooms on the map are
classes which implement the interface
com.planet_ink.coffee_mud.Locales.interfaces.Room. If a MOB is to have
a permanent existence, it must also have a starting room, or a place to
rejuvenate into when necessary. If a MOB does not have a starting room,
then its death, when that death comes, will be forever.</p>
      <pre>MOB mob = CMClass.getMOB( "MyNewMOB" );<br />Room room = CMLib.map().getRoom( "Midgaard#3504" );<br /><br />mob.setStartRoom( room ); // this mob will rejuvenate into this room.<br />mob.basePhyStats().setRejuv( 500 ); // 30 minutes rejuvenation time<br />mob.recoverPhyStats(); // remember this command?!<br /><br />mob.bringToLife( room, true ); // tadah!<br /></pre>
      <p>And THAT's all there is
to bring a standard mob to life. Now,
generic items require an additional step:</p>
      <pre>Item item = CMClass.getItem( "GenItem" );<br />Room room = CMLib.map().getRoom( "Midgaard#3504" );<br /><br />item.text();<br />item.recoverPhyStats();<br />room.addItem( item );<br />room.recoverRoomStats();<br /></pre>
      <p>The call to the <code>text()</code>
method and the seemingly
redundant call to <code>Item.recoverPhyStats()</code>
(which we know is already in the item constructor), ensures that some
of the internal structures of the Generic MOB are properly set. Of
course, you may want to save this room to the database to make the
situation permanent, but all of this is usually done from inside
CoffeeMud using the CREATE, MODIFY, and DESTROY commands anyway.
Speaking of destroy, destroying a mob for good is even easier than
creating one:</p>
      <pre>Room room = CMLib.map().getRoom( "Midgaard#3504" );<br />for( int i = 0; i &lt; room.numInhabitants(); i++ )<br />{<br />  MOB mob = room.fetchInhabitant( i );<br />  mob.destroy();<br />}<br /></pre>
      <img src="images/sword.jpg" alt="Items" />
      <h2><a name="ITEMS" id="ITEMS">Items:</a></h2>
      <p>A Custom Item may or may
not belong to any particular package,
though it is important that the <code>ID()</code>
of the Item be unique in the system. A custom Item imports the same
packages mentioned in the first section of this document under Complete
Default Import List as well as (in this case)
com.planet_ink.coffee_mud.Items.Weapons.StdWeapon because our first
sample item extends it.</p>
      <p>An Item class must extend
either StdItem or GenItem, StdWeapon
or GenWeapon, StdRideable or GenRideable, StdArmor or GenArmor
depending on the basic capabilities, and customizability you would
like. Although Generic objects are more customizable at run-time, they
also take a long time for the system to load and build, and take up a
lot of database disk space. For this reason, using Standard instead of
Generic wherever possible is always good. There are generally two good
reasons to be coding your own Items: because you have a particular kind
of item that is used prolifically in your world, and you want to save
memory by coding it as a special item that extends StdItem or StdWand,
or because you want to code special item capabilities by creating your
own class that both extends one of the base item classes and has the
same <code>ID()</code>
string of that class. The directory for your custom coded Item objects
should be specified using the "ITEMS", "WEAPONS", "ARMOR", "CLANITEMS",
or "MISCMAGIC" entries in the coffeemud.ini file. See the section above
on Rebuilding CoffeeMud for more information on this feature.</p>
      <p>Each Item must also have
a custom <code>ID()</code>
method as
shown below. Notice that the <code>ID()</code>
is the same as the name
of the class. This is no accident -- this is required!</p>
      <pre>public class MyNewSword extends com.planet_ink.coffee_mud.Items.Weapons.StdWeapon<br />{<br />  public String ID(){ return "MyNewSword"; }<br /><br />  public MyNewSword()<br />  {<br />     super();<br />  }<br />}<br /></pre>
      <p>All of your customizing
will be done inside the constructor:
name, displayText, description, etc, etc.</p>
      <pre> public MyNewSword()<br /> {<br />   super();<br /><br />   setName( "a super sword" );<br />   setDescription( "A long super duper sword!" );<br />   setDisplayText( "Someone left their super sword here." );<br />   setSecretIdentity( "" );<br />   setMaterial( RawMaterial.RESOURCE_STEEL );<br />   setWeaponDamageType( Weapon.TYPE_SLASHING );<br />   setWeaponClassification( Weapon.CLASS_SWORD );<br /><br />   setBaseValue( 500 );<br />   basePhyStats().setDisposition( PhyStats.IS_GLOWING );<br />   basePhyStats.setWeight( 25 );<br />   basePhyStats.setAttackAdjustment( 10 );<br />   basePhyStats.setDamage( 15 );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>What is shown above is
entirely sufficient for the creation of
a normal StdWeapon . The material, weight, attack and damage describe
it completely. You'll even notice that by setting a disposition flag,
we have made the sword glow! Now, what if we wanted a missile weapon?</p>
      <pre> public MyNewBow()<br /> {<br />   super();<br /><br />   setName( "a super bow" );<br />   setDescription( "A long super duper bow!" );<br />   setDisplayText( "Someone left their super bow here." );<br />   setSecretIdentity( "" );<br /><br />   setMaterial( RawMaterial.RESOURCE_OAK );<br />   setBaseValue( 5000 );<br />   basePhyStats.setWeight( 15 );<br />   basePhyStats.setAttackAdjustment( 20 );<br />   basePhyStats.setDamage( 5 );<br />   setWeaponDamageType( Weapon.TYPE_PIERCING );<br />   setWeaponClassification( Weapon.CLASS_RANGED );<br />   setRanges( 1, 5 );<br />   setAmmunitionType( "arrows" );<br />   recoverPhyStats();<br /> }<br /><br /> public void recoverPhyStats()<br /> {<br />   basePhyStats().setDamage(1 * basePhyStats().level());<br />   basePhyStats().setAttackAdjustment(basePhyStats().level()*2);<br />   super.recoverPhyStats();<br /> }<br /></pre>
      <p>You'll notice we added
two new methods, <code>setRanges()</code>,
and <code>setAmmunitionType()</code>.
With the former, we specify that this is a ranged-only weapon, usable
from range 1 (0=melee) to range 5. The ammunition type specifies that
it uses arrows. We also added the method <code>recoverPhyStats()</code>
in order to have the attack and damage for the weapon always reflect
the level of the item. </p>
      <p>So those are weapons.
Other classes, however, have different
requirements
altogether. For instance, if class extends
com.planet_ink.coffee_mud.Items.Armor.StdArmor:</p>
      <pre> public MyNewArmor()<br /> {<br />   super();<br /><br />   setName( "a super bracer" );<br />   setDescription( "A super duper bracer" );<br />   setDisplayText( "Someone left their super bracer here." );<br />   setSecretIdentity( "" );<br /><br />   setMaterial( RawMaterial.RESOURCE_STEEL );<br />   setBaseValue( 100 );<br />   basePhyStats.setWeight( 5 );<br />   basePhyStats.setArmor( 5 );<br />   setRawProperLocationBitmap( Wearable.WORN_LEFT_WRIST|Wearable.WORN_RIGHT_WRIST );<br />   setRawLogicalAnd( false );<br />   recoverPhyStats();<br /> }<br /><br /> public void recoverPhyStats()<br /> {<br />   basePhyStats().setArmor(2+(basePhyStats().level()/2));<br />   super.recoverPhyStats();<br /> }<br /></pre>
      <p>In this case, we made a
bracer wearable on both left and right
wrists. If it were something that could only be worn on both wrists at
the same time (like handcuffs), then the RawLogicalAnd value would have
been true. Now, a class extending
com.planet_ink.coffee_mud.Items.Basic.StdContainer:</p>
      <pre> public MyNewBag()<br /> {<br />   super();<br /><br />   setName( "a super bag" );<br />   setDescription( "A super duper bag" );<br />   setDisplayText( "Someone left their super bag here." );<br />   setSecretIdentity( "" );<br /><br />   setBaseValue( 50 );<br />   setDoorsNLocks( false, true, false, false, false, false );<br />   setKeyName( "" );<br />   setMaterial( RawMaterial.RESOURCE_LEATHER );<br />   basePhyStats.setWeight( 1 );<br />   setCapacity( 100 );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>When setting the capacity
of a container, remember that it
must also be able to hold its own weight! Also, note the lids and locks
flags have made this container lidless and lockless and always open. Of
course, without a lock, setting a key would be silly! Now, a class
extending com.planet_ink.coffee_mud.Items.Basic.StdDrink will create a
drinkable container:</p>
      <pre> public MyNewCup()<br /> {<br />   super();<br /><br />   setName( "a super cup" );<br />   setDescription( "A super duper cup" );<br />   setDisplayText( "Someone left their super cup here." );<br />   setSecretIdentity( "" );<br /><br />   setMaterial( RawMaterial.RESOURCE_LEATHER );<br />   setBaseValue( 5 );<br />   setLiquidHeld( 2000 );<br />   setLiquidRemaining( 2000 );<br />   setThirstQuenched( 500 );<br />   setLiquidType( RawMaterial.RESOURCE_MILK );<br />   basePhyStats.setWeight( 1 );<br />   setCapacity( 0 );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>The StdDrink created
above is an enormous cup of milk! You'll
notice the capacity is 0, meaning that mundane objects cannot be stored
in it. Now, a class extending
com.planet_ink.coffee_mud.Items.Basic.StdFood:</p>
      <pre> public MyNewFood()<br /> {<br />   super();<br /><br />   setName( "a super crumb" );<br />   setDescription( "A super duper crumb" );<br />   setDisplayText( "Someone left their super crumbs." );<br />   setSecretIdentity( "" );<br /><br />   setBaseValue( 1 );<br />   setMaterial( RawMaterial.RESOURCE_MEAT );<br />   setNourishment( 500 );<br />   basePhyStats.setWeight( 1 );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>Now, the items extending
com.planet_ink.coffee_mud.Items.Basic.StdRideable resemble the MOB of
the same name, and thus, have identical modifications.</p>
      <pre> public MyNewBed()<br /> {<br />   super();<br /><br />   setName( "a bed" );<br />   setDescription( "A bed" );<br />   setDisplayText( "A bed is here" );<br />   setSecretIdentity( "" );<br /><br />   setBaseValue( 100 );<br />   setMobCapacity( 2 );<br />   setRideBasis( Rideable.RIDEABLE_SLEEP );<br />   basePhyStats.setWeight( 100 );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>A pile of money extends
class
com.planet_ink.coffee_mud.Items.Basic.StdCoins, and is simplest of all:</p>
      <pre> public MyNewMoney()<br /> {<br />   super();<br /><br />   setName( "a pile of coins" );<br />   setDescription( "A pile of coins" );<br />   setDisplayText( "Someone left their money here." );<br />   setSecretIdentity( "" );<br /><br />   setBaseValue( 0 );<br />   setMaterial( RawMaterial.RESOURCE_GOLD );<br />   setNumberOfCoins( 1000 ); // 1000 coins!<br />   setDenomination( 1.0 ); // each coin worth 1.0 basic gold<br />   basePhyStats.setWeight( 1 );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>Notice that the base
value of the coins is 0, it's the other
methods that truly determine its value. Now, to make a magical pill,
our class should extend
com.planet_ink.coffee_mud.Items.MiscMagic.StdPill:</p>
      <pre> public MyNewPill()<br /> {<br />   super();<br /><br />   setName( "a super pill" );<br />   setDescription( "A super duper pill" );<br />   setDisplayText( "Someone left their super pill." );<br />   setSecretIdentity( "" );<br /><br />   setBaseValue( 1 );<br />   setMaterial( RawMaterial.RESOURCE_MEAT );<br />   setNourishment( 500 );<br />   basePhyStats.setWeight( 1 );<br />   setSpellList( "Spell_Sleep;Prayer_CureLightWounds" );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>The spells cast on the
eater are listed by their Class names,
separated by semicolons. The secret identity is also trimmed out, since
the system will handle that automaticallyy. Also notice that the
StdPill resembles StdFood except for the addition of the setSpellList
method. In the exact same way, the
com.planet_ink.coffee_mud.Items.MiscMagic.StdPotion class resembles the
StdDrink class except that it has an identical setSpellList method
added to IT. So, in the interests of saving a little sand for future
generations, I would enumerate the StdPotion. We can, however, show off
another class which extends
com.planet_ink.coffee_mud.Items.MiscMagic.StdScroll:</p>
      <pre> public MyNewScroll()<br /> {<br />   super();<br /><br />   setName( "a super scroll" );<br />   setDescription( "A super duper scroll" );<br />   setDisplayText( "Someone left their super scroll." );<br />   setSecretIdentity( "" );<br />   setBaseValue( 100 );<br /><br />   setMaterial( RawMaterial.RESOURCE_PAPER );<br />   setUsesRemaining( 50 );<br />   basePhyStats.setWeight( 1 );<br />   setScrollSpells( "Spell_Sleep;Prayer_CureLightWounds" );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>Not too difficult, right?
Looks like the other two, but the
spell setting method has a different name. Now, let's look at a sample
of a class extending com.planet_ink.coffee_mud.Items.MiscMagic.StdWand:</p>
      <pre> public MyNewWand()<br /> {<br />   super();<br /><br />   setName( "a wand" );<br />   setDescription( "A magic wand" );<br />   setDisplayText( "Someone left their magic wand." );<br />   setSecretIdentity( "" );<br /><br />   setBaseValue( 1000 );<br />   setMaterial( RawMaterial.RESOURCE_OAK );<br />   basePhyStats.setWeight( 1 );<br />   setSpell( CMClass.getAbility( "Spell_Fireball" ) );<br />   setUsesRemaining( 50 );<br />   recoverPhyStats();<br /> }<br /></pre>
      <p>In this case, we made use
of the "uses remaining" field to set
the number of charges for the wand. The way the spell is set is also
different. A wand may only have one spell, and the actual Ability
object for the spell must be passed in, instead of just the class name
as we did before. You will find that this is also how the classes
extending com.planet_ink.coffee_mud.Items.MiscMagic.StdStaff work. The
StdStaff resembles the StdWeapon we did above, except that the
additional setSpell and setUsesRemaining calls become appropriate to
the constructor.</p>
      <p>The next thing we will
look at is adding effects and behaviors
to Items. Behavior addition (despite the fact that there is really only
one behavior that works with Items) will look familiar. The only
difference between this and the MOB example above is the fact that we
are setting a parameter on the Behavior before adding it.</p>
      <pre>Behavior B = CMClass.getBehavior( "Emoter" );<br />B.setParms( "min=1 max=20 chance=75;makes strange sounds" );<br />addBehavior( B );<br /></pre>
      <p>Adding normal effects as
properties is also similar to mobs...</p>
      <pre>Ability A = CMClass.getAbility( "Prop_HaveResister" );<br />A.setMiscText( "fire acid 50%" );<br />A.addNonUninvokableEffect( A );<br /></pre>
      <p>The above Effect will
allow anyone who owns the item to resist
fire and acid at 50%! And again, as with mobs, these commands are best
put in the constructor of the item before the recoverPhyStats() call.</p>
      <p>There is also the
advanced topic of extending the capabilities
of the existing Item classes. As mentioned previously, this consists in
creating your own java classes with the same class name and ID() string
methods as the base CoffeeMud Item classes, and the adding the
reference to your custom class to the relevant coffeemud.ini file's
entries after the %DEFAULT% string. Now, adding or extending the
capabilities of these classes typically means both adding your own
methods, and extending the importing existing methods in those classes.
The most important of those existing methods are discussed above in the
Core Topics, namely okMessage and executeMsg. However, there are many
other methods which might be extended to the end of altering or
enhancing basic aspects of the mud. Those are numerated both in the
classes you are extending, in
com.planet_ink.coffee_mud.Items.interfaces.Item.java, and in other
interface files in that directory. Consult the CoffeeMud java docs for
more information.</p>
      <h3><a name="itemlife" id="itemlife">Creating and
Destroying Items</a></h3>
      <p>As with mobs, the
following instructions are supplemental, and
unnecessary. Once you have created your new Item, modified your INI
file, and rebooted your CoffeeMud server, you need only use the CREATE
and other Archon commands to make use of it. If, for some reason, you
want to know HOW these commands do their work, however, here it is.</p>
      <p>To bring an Item into
existence, an item must have somewhere
to exist! Items can belong to either Rooms, as mobs are, or they can
belong to mobs themselves. This means that Items actually have two
different creation mechanisms. Here is an example of each, starting
with the creation of an Item in a Room:</p>
      <pre>Item item = CMClass.getItem( "MyNewItem" );<br />Room room = CMLib.map().getRoom( "Midgaard#3504" );<br /><br />room.addItem( item );<br />room.recoverRoomStats();<br /></pre>
      <p>A room is grabbed off the
map, and the item is added to the
room using the <code>addItem()</code>
method. Then the room recover is called to make the room react to the
addition of the item. Now, generic items require an additional step:</p>
      <pre>Item item = CMClass.getItem( "GenItem" );<br />Room room = CMLib.map().getRoom( "Midgaard#3504" );<br /><br />item.text();<br />item.recoverPhyStats();<br />room.addItem( item );<br />room.recoverRoomStats();<br /></pre>
      <p>The call to the <code>text()</code>
method and the seemingly
redundant call to <code>Item.recoverPhyStats()</code>
(which we know is already in the item constructor), ensures that some
of the internal structures of the Generic Item are properly set. Of
course, these items are one-shot items, meaning that they are not
generated to exist on the map forever and ever.</p>
      <pre>Item item = CMClass.getItem( "MyNewItem" );<br />Room room = CMLib.map().getRoom( "Midgaard#3504" );<br /><br />item.basePhyStats().setRejuv( 500 ); // 30 minutes rejuvenation time<br />item.recoverPhyStats();<br />room.addItem( item );<br />room.recoverRoomStats();<br />room.startItemRejuv();<br /></pre>
      <p>In this case, we wanted
the item to be rejuvenating. That
means that, when the item is removed from the room by a player, the
item will reset at some point in the future. If the rejuv ticks count
is set to 0, the item will not reset. In the example above, the count
is set to 500 so that the item will reset. However, the rejuvenation is
not actually activated until the room item rejuvs are set. This is done
with the last method call to <code>startItemRejuv()</code>,
which
handles the rejuv resets on all items in the room.</p>
      <p>In the previous section,
we saw how items are given to mobs by
simply calling the <code>addItem()</code>
method, so this will not be repeated. Regardless of where or how the
item is created, however, it is destroyed the same way. With a simple
call to the <code>destroy()</code>
method on the item. Here is an
example of destroying all the items in a room.</p>
      <pre>Room room = CMLib.map().getRoom( "Midgaard#3504" );<br /><br />for( int i = room.numItems() - 1; i &gt;= 0; i-- )<br />{<br />  Item item = room.fetchItem( i );<br />  item.destroy();<br />}<br /></pre>
      <img src="images/clown.jpg" alt="Behaviors" />
      <h2><a name="BEHAVS" id="BEHAVS">Behaviors</a></h2>
      <p>A Behavior is defined as
a property of an item, mob, exit, or
room which takes proactive (as opposed to REactive) steps on behalf of
its host. Examples of Behaviors include aggressiveness, mobility,
auto-emoting, and scripting. Behaviors import the same packages
mentioned in the first section of this document under Complete Default
Import List as well as (in this case)
com.planet_ink.coffee_mud.Behaviors.StdBehavior because our sample
behavior extends it. Custom behaviors are loaded at boot-time by adding
references to them to the BEHAVIORS entry in your coffeemud.ini file.
Let's take a look at a sample Behavior and see how they are put
together:</p>
      <pre>public class Ravenous extends com.planet_ink.coffee_mud.Behaviors.StdBehavior<br />{<br />  public String ID(){ return "Ravenous"; }<br />  public String name(){ return "Ravenous Eater"; }<br /></pre>
      <p>Our first step, as seen
above, is to make sure we define an <code>ID()</code>
method with the classes name, just as we do in other CoffeeMud objects.
Notice that the <code>ID()</code>
is the same as the name of the class. This is no accident -- this is
required! The next step is to give the Behavior a name, which is
entirely unimportant to players, but helpful for Archons.</p>
      <pre>  protected int canImproveCode(){ return Behavior.CAN_MOBS; }<br />  public long flags(){ return 0; }<br />  public boolean grantsAggressivenessTo( MOB M ){ return false; }<br /></pre>
      <p>Next are some important
flags that tell the CoffeeMud system
some important things about your behavior. The first method (<code>canImproveCode()</code>)
tells the behavior whether it is properly used on Mobs, or Items,
Rooms, Exits, or all of these. In this case, our behavior only affects
mobs. The next method (<code>flags()</code>)
tells the system certain
things about the behavior by returning values such as
Behavior.FLAG_MOBILITY, or Behavior.FLAG_TROUBLEMAKING. The last method
(<code>grantsAggressivenessTo()</code>)
says whether or not this method
would necessary cause the host mob to attack the mob (M) in the
parameter.</p>
      <pre>  public void startBehavior( PhysicalAgent forMe )<br />  {}<br /></pre>
      <p>The next method, seldom
used, is still quite important.
startBehavior receives as its parameter the brand new host of this
behavior. If the behavior instance needs to do any variable or other
preparation to either the behaving object host (forMe) or itself, it
should do so here.</p>
      <pre>  public String getParms(){ return super.getParms(); }<br />  public void setParms( String parameters )<br />  {<br />    super.setParms( parameters );<br />  }<br /></pre>
      <p>These methods, part of
the StdBehavior and Behavior interface,
are shown here just to make you aware of how parameter strings passed
to behaviors are accessed. Sometimes prepatory code is also executed
inside a setParms method, for instance. Normally these methods would
not appear in your own instance of a Behavior.</p>
      <pre>  public boolean tick( Tickable ticking, int tickID )<br />  {<br />    MOB mob = getBehaversMOB( ticking ); // returns mob, if ticking is a mob. Returns mob owner, if ticking is an item<br />    Room room = getBehaversRoom( ticking ); // whatever the ticking object is, this will return its location<br />    if( ( mob == null ) || ( room == null ) || ( tickID != Host.MOB_TICK ) )<br />    {<br />      return super.tick( ticking, tickID );<br />    }<br /></pre>
      <p>Now we get to the nitty
gritty of the Behaviors work. A
behavior gets all or almost all of its work done in a tick method. If
you have not read the Core Topic above about the tick method, you
should definitely do so! In this example, we call two internal
StdBehavior methods to get some important starting information about
the behaving object host of the behavior. In this example, our behaving
object host will be a mob. However, these methods may still
intelligently return Item owners, or Exit rooms if the host is other
than a mob. The ticking parameter will always be the behaving object
host.</p>
      <p>The next line checks to
see if our host mob exists, and is in
a room. We also check to see if the tickID is the valid mob ticking id.
If our host had been an Item, Exit, or Room, this tickID would no
longer be Tickable.TICKID_MOB, but would be
Tickable.TICKID_ITEM_BEHAVIOR, Tickable.TICKID_ROOM_BEHAVIOR, or
Tickable.TICKID_EXIT_BEHAVIOR. Since our host, in this case, is a Mob,
we check for Tickable.TICKID_MOB.</p>
      <pre>    if( ( !canActAtAll( mob ) ) || ( !canFreelyBehaveNormal( mob ) ))<br />    {<br />      return super.tick( ticking, tickID );<br />    }<br /></pre>
      <p>Our next step is to call
a couple more internal StdBehavior
methods. The first (<code>canActAtAll()</code>)
returns true if the mob
is alive, awake, and mobile. The second method (<code>canFreelyBehaveNormal()</code>)
returns true if the mob is not currently in combat, not charmed or
following anyone, and is not severely injured. We want our ravenous mob
to follow this behavior only in the best of health and mood.</p>
      <pre>    Item eatible = null;<br />    for( int i = 0; i &lt; mob.numItems(); i++ )<br />    {<br />      Item I = mob.getItem( i );<br />      if( ( I != null ) &amp;&amp; ( I instanceof Food ) )<br />      {<br />        eatible=I;<br />      }<br />    }<br /></pre>
      <p>Next, we iterate through
the mob's inventory to find the last
instance of a piece of food.</p>
      <pre>    if( eatible != null)<br />    {<br />      room.show( mob, eatible, null, "&lt;S-NAME&gt; gobble(s) up &lt;T-NAMESELF&gt;." );<br />      return true;<br />    }<br /></pre>
      <p>If some food was found,
the mob will eat it. Now, practically
speaking, the mob will quickly devour and use up any and all food which
it may have had to begin with. What we decide to do when the mob does
NOT have food, therefore, is just as important.</p>
      <pre>    MOB mobToHitUp = room.fetchRandomInhabitant();<br />    if( ( mobToHitUp == null )<br />    ||( mobToHitUp == mob )<br />    ||( CMLib.dice().rollPercentage() &gt; 75 ))<br />    {<br />      return true;<br />    }<br /></pre>
      <p>Since our mob is hungry,
and another mob is the most likely
source of food, we will pick a random inhabitant of the room, which is
not ourselves, 25% of the time. Otherwise, we just return true, and try
again on the next tick.</p>
      <pre>    Item I = mobToHitUp.getRandomItem();<br />    if( ( I != null ) &amp;&amp; ( I instanceof Food ) )<br />    {<br />      eatible = I;<br />    }<br /><br />    if( eatible == null )<br />    {<br />      return true;<br />    }<br /></pre>
      <p>Next we will pick a
random piece of inventory from that mob,
and see if it is food. If not, we return true and try again on the next
tick.</p>
      <pre>    CMLib.commands().postSay( mob, mobToHitUp, "May I have some of your " + eatible.name() + "?" , false, false );<br /><br />    return true;<br />  }<br /></pre>
      <p>And lastly, since we have
picked a random mob in the room, and
seen that he has food, we will ask him for it! If it's a player, then
perhaps he might even give us some. If we are given food, we will eat
it on the next tick for sure!</p>
      <pre>  public void executeMsg( Environmental affecting, CMMsg msg )<br />  {}<br /><br />  public boolean okMessage( Environmental oking, CMMsg msg )<br />  {<br />    return true;<br />  }<br />}<br /></pre>
      <p>The above two methods are
shown here just to remind you that,
although a behavior's PRIMARY purpose is to be proactive in a tick
method, a behavior also has the ability to preview and respond to
messages affecting the host behaving object. That object will always be
identified in the affecting and oking parameters respectively. If these
two methods mean nothing to you, you should definitely go back and read
the Core Topic on message passing.</p>
      <img src="images/cloak.jpg" alt="Character Classes" />
      <h2><a name="CLASSES" id="CLASSES">Character Classes</a></h2>
      <p>A Character Class, in
CoffeeMud, is the carreer being followed
by the player. Armor and weapon choices, skill and spell access, as
well as score advancements all depend on the Character Class chosen by
the player. Thankfully, despite all this weighty responsibility,
Character Classes are not difficult to code. CharClasses import the
same packages mentioned in the first section of this document under
Complete Default Import List as well as (in this case)
com.planet_ink.coffee_mud.CharClasses.StdCharClass because our sample
class extends it. Your custom classes need to be listed in your
coffeemud.ini file under the CHARCLASSES entry. Aside from making
custom classes, you can also extend an existing class, return an
identical <code>ID()</code>
string, and then list it at the end of the
aforementioned entry in the coffeemud.ini file. Now, let's take a look
at a simple one here:</p>
      <pre>public class NormalGuy extends com.planet_ink.coffee_mud.CharClasses.StdCharClass<br />{<br /></pre>
      <p>Our Normal Guy character
class will define all of the basic
elements of a filled-out character class.</p>
      <pre>  public String ID()<br />  {<br />    return "NormalGuy";<br />  }<br /><br />  public String baseClass()<br />  {<br />    return ID();<br />  }<br /></pre>
      <p>The first methods above
are the unique Character Class ID and
the Base Class ID of the class. The Class ID must be a unique
identifier. The <code>baseClass()</code>
method takes a bit of explaining. If your CoffeeMud system is using the
default SubClassing system, the baseClass will define which classes may
be switched between by a player, as well as which classes are available
to choose from when a new player is created. Fighter, Monk, Paladin,
Ranger, and Barbarian, for instance, all have a baseClass of "Fighter".
This means that the Fighter class is one of the classes which may be
chosen by a new player (since it's <code>ID()</code>
and <code>baseClass()</code>
are the
same), and that any of the baseClass() "Fighter" classes may switch
amongst each other. If your CoffeeMud system is using the multi-class
or single classing system, this method is irrelevant.</p>
      <pre>  public String name()<br />  {<br />    return "Normal Guy";<br />  }<br /><br />  public String name( int classLevel )<br />  {<br />    return name();<br />  }<br /></pre>
      <p>Our next method, <code>name()</code>,
is the default
displayable name of your class. The next method <code>name(
int
classLevel )</code>
is, in this case, simply returning the default name again. However, if
you like, your character classes may have different names at different
class levels. Simply check the classLevel and return a different
string! As standard practice, however, class level 0 should always
return the default name. Remember that Class Levels are different from
Player Levels. A Player may, in a multi-classing system, have numerous
levels in numerous classes. The Class Level represents how many levels
the player has gained in this character class ONLY!</p>
      <pre>  protected String[] names = null;<br /><br />  public String[] nameSet()<br />  {<br />    if( names != null )<br />    {<br />      return names;<br />    }<br /><br />    names = new String[1];<br />    names[0] = name();<br />    return names;<br />  }<br /></pre>
      <p>The <code>nameSet()</code>
method really only needs to be
extended and re-implemented when there are more than 1 available names
for your class. Its purpose is to return a string list of all the names
that this class may go by. As you can see from the above code, by
default, the StdCharClass will nicely handle classes with just one
name. However, the code above will need to be altered in your own
character class if you choose to make one with multiple names.</p>
      <pre>  public String getHitPointsFormula()<br />  {<br />    return "((@x6&lt;@x7)/3)+(2*(1?6))";<br />  }</pre>
      <p>Next come the hit point
ranges. When a player with this class
gains a level,these values will determine hit points gained based on
class and stats.&nbsp;See the Archon help on Math Formulas (or just
Formulas) for information on how to write formulas. &nbsp;The
variables
that can be included are: @x1: Players current class level, @x2:
Players adjusted Strength, @x3: Players Max adjusted Strength, @x4:
Players adjusted Dexterity, @x5: Players Max adjusted Dexterity, @x6:
Players adjusted Constitution, @x7: Players Max adjusted Constitution,
@x8: Players adjusted Wisdom, @x9: Players adjusted Intelligence</p>
      <pre>  public int getPracsFirstLevel()<br />  {<br />    return 3;<br />  }<br /><br />  public int getTrainsFirstLevel()<br />  {<br />    return 1;<br />  }<br /><br />  public int getBonusPracLevel()<br />  {<br />    return 0;<br />  }<br /></pre>
      <p>The next two methods
define the starting Training and Practice
points for this Character Class. The BonusPracLevel method tells us how
many bonus practices (above the number determined the WISDOM/4 formula)
which the player will receive every level.</p>
      <pre>  public int getAttackAttribute()<br />  {<br />    return CharStats.STAT_STRENGTH;<br />  }<br /><br />  public int getBonusAttackLevel()<br />  {<br />    return 1;<br />  }<br /></pre>
      <p>And here is an method
defining which of the 6 primary
Character Attributes (Strength, Intelligence, Wisdom, Dexterity,
Constitution, or Charisma) are used to determine any attack bonuses
whenever the player gains a level. Usually this is Strength. The number
of bonus attack points received by a player when a level is gained is
determined by dividing the players score in this attribute by 6, and
then adding the value returned by <code>getBonusAttackLevel()</code>.</p>
      <pre>  public String getManaFormula()<br />  {<br />    return "((@x4&lt;@x5)/3)+(1*(1?4))";<br />  }</pre>
      <p>This method determines
how much mana a player receives when
they gain a level in this class. &nbsp;See the Archon help on Math
Formulas (or just Formulas) for information on how to write formulas.
&nbsp;The variables that can be included are: &nbsp;@x2:
Players
adjusted Wisdom, @x3: Players Max adjusted Wisdom, @x4: Players
adjusted Intelligence, @x5: Players Max adjusted Intelligence, @x6:
Players adjusted Attack Attr&nbsp; @x7: Players Max adjusted Attack
Attr,
@x8: Players adjusted Charisma, @x9: Players adjusted Constitution</p>
      <pre>  public int getLevelsPerBonusDamage()<br />  {<br />    return 25;<br />  }<br /></pre>
      <p>This score determines how
many levels a player must make, in
this class, before they will gain a bonus point of damage to all damage
rolls.</p>
      <pre>  public String getMovementFormula()<br />  {<br />    return "10*((@x2&lt;@x3)/18)"; <br />  }</pre>
      <p>And lastly for our
scores, this method will determine how many
movement points a player receives when they gain a level.&nbsp;See
the
Archon help on Math Formulas (or just Formulas) for information
on how to write formulas. &nbsp;The variables that can be included
are:
@x1: Players current class level, @x2: Players adjusted Strength, @x3:
Players Max adjusted Strength, @x4: Players adjusted Dexterity, @x5:
Players Max adjusted Dexterity, @x6: Players adjusted Constitution,
@x7: Players Max adjusted Constitution, @x8: Players adjusted Wisdom,
@x9: Players adjusted Intelligence</p>
      <pre>  public int allowedArmorLevel()<br />  {<br />    return CharClass.ARMOR_CLOTH;<br />  }<br /></pre>
      <p>The CharClass interface
defines a method called "armorCheck"
which returns true if the player is in compliance with armor
requirements. This method does its work by checking the <code>allowedArmorLevel()</code>
method. This method returns an equate defined in the CharClass
interface which may specify ANY armor, CLOTH level, armor, LEATHER (or
worse) armor, or NON-METAL armor. You should check the CharClass
interface for any other ARMOR_* definitions which may be added from
time to time.</p>
      <pre>  public int allowedArmorLevel()<br />  {<br />    return CharClass.ARMOR_CLOTH;<br />  }<br /><br />  protected int requiredArmorSourceMinor()<br />  {<br />    return -1;<br />  }<br /><br />  protected String armorFailMessage()<br />  {<br />    return "&lt;s-name&gt; fumble(s) &lt;s-his-her&gt; &lt;skill&gt; due to &lt;s-his-her&gt; armor!";<br />  }<br /></pre>
      <p>The The StdCharClass will
automaticallyy enforce armor
requirements whenever a class skill is used, provided these methods are
defined. The <code>allowedArmorLevel()</code>
method returns an equate defined in the CharClass interface which may
specify ANY armor, CLOTH level, armor, LEATHER (or worse) armor,
METAL-ONLY, or NON-METAL armor. You should check the CharClass
interface for any other ARMOR_* definitions which may be added from
time to time.</p>
      <p>While the <code>armorFailMessage()</code>
method is pretty
self explanatory, the requiredArmorSourceMinor may not be. The later
method returns the MINOR code of the SOURCE code of the message
generating the skill use. Typically this method will either return -1
for non spell casters, or CMMsg.TYP_CAST_SPELL for spell casters. See
the Core Topics for more information on what the heck a source code of
a message might be.</p>
      <pre>  public int allowedWeaponLevel()<br />  {<br />    return CharClass.WEAPONS_THIEFLIKE;<br />  }<br /><br />  private Set&lt;Integer&gt; disallowedWeapons = buildDisallowedWeaponClasses();<br />  public Set&lt;Integer&gt; disallowedWeaponClasses( MOB mob )<br />  {<br />    return disallowedWeapons;<br />  }<br /><br />  private Set&lt;Integer&gt; requiredWeaponMaterials = buildRequiredWeaponMaterials();<br />  public Set&lt;Integer&gt; requiredWeaponMaterials()<br />  {<br />    return requiredWeaponMaterials;<br />  }<br /></pre>
      <p>The StdCharClass will
automaticallyy enforce weapon
restrictions whenever a weapon attack is made, provided these methods
are defined. The <code>allowedWeaponLevel()</code>
method returns an equate defined in the CharClass interface which may
specify ANY weapons, DAGGER only, THIEF-like weapons, WOODEN weapons,
and several others. You should check the CharClass interface for other
WEAPONS_* definitions which may be added from time to time.</p>
      <p>The <code>disallowedWeaponClasses(
MOB mob )</code> and <code>requiredWeaponMaterials()</code>
methods return HashSet objects which, due to the method calls in
StdCharClass seen above, are totally derivative of the value you
already put in <code>allowedWeaponLevel()</code>.
In other words, so
long as you include the <code>allowedWeaponLevel()</code>
method, you
should also include those next four methods, exactly as you see them.</p>
      <pre>  public int getLevelCap() {return -1;}<br /></pre>
      <p>Although not often used,
you can set a level cap for the
character class by returning some number above -1 from the getLevelCap
method. The engine will take care of the rest. </p>
      <pre>  public int availabilityCode()<br />  {<br />    return Area.THEME_FANTASY;<br />  }<br /></pre>
      <p>The method <code>availabilityCode()</code>
defines how
players
can access this race. Possible values for this constant include:
'Area.THEME_FANTASY' (makes the class available for players to choose
when creating fantasy characters),
'Area.THEME_FANTASY|Area.THEME_SKILLONLYMASK' (makes the class
available to spells or Skills, but not for player creation), or '0'
(the class is not available to spells or for player creation.)</p>
      <pre>  public NormalGuy()<br />  {<br />    super();<br />    maxStat[CharStats.STAT_CHARISMA] = 10;<br />  }<br /><br />  public void initializeClass()<br />  {<br />    CMLib.ableMapper().addCharAbilityMapping( ID(), 1,  "Skill_Write",  50,<br />                                              "", true, false, new Vector(), "" );<br />    CMLib.ableMapper().addCharAbilityMapping( ID(), 1,  "Skill_Recall",  0,<br />                                              "", true, false, new Vector(), "" );<br />    CMLib.ableMapper().addCharAbilityMapping( ID(), 1,  "Skill_Climb",  0,<br />                                              "", true, false, new Vector(), "" );<br />    CMLib.ableMapper().addCharAbilityMapping(ID(), // class/race to assign the skill to<br />                                             1, // level the skill is qualified for<br />                                             "Skill_Swim", // the java ID of the ability to qualify for<br />                                             0, // default proficiency to give after gaining<br />                                             "", // any misc parameters to pass to the Skill_Swim skill<br />                                             false, // true for the class to gain automatically, false to qualify<br />                                             false, // whether this skill is unlisted for this class<br />                                             CMParms.parseSemicolons("Skill_Climb;Skill_Write", true ), // list of skills required to gain this one<br />                                             "-LOCALE +UNDERWATER" // mask to apply to class members wanting this skill<br />                                           );<br />  }<br />}<br /> <br /></pre>
      <p>And now, after a few
methods to flag our construction, work,
we come to our constructor! The Constructor for every character class
defines any special maximums for the primary attributes. This is done
by setting the appropriate value in the <code>maxStat[]</code>
array
for the class. By default, 18 is the maximum score for all primary
attributes.</p>
      <p>The second method is
found in all CMObject, and is the
initializeClass() method. This method is called after all classes have
been loaded, but before the map is loaded. The method is called once on
every class, but only during initialization. In Character classes, it
establishes the qualifying and bonus skills for the class. This is done
through repeated calls to one of the several <code>CMLib.ableMapper().addCharAbilityMapping()</code>
methods. The first parameter of the method is the <code>ID()</code>
value of the Character Class itself, followed by the level at which
this class gains or qualifies for the skill. Next is the <code>ID()</code>
value of the Ability to allow this
class to qualify for, followed by the default proficiency which this
class displays in the skill (typically 0). The next parameter are any
special parameters that affects the way this class uses the skill,
followed by a boolean which establishes whether the player will receive
this skill automaticallyy when he or she gains the appropriate level,
or whether they merely qualify for the skill. The next parameter,
almost always false, determines whether the skill is "secret" for this
class. Secret skills are qualified for (or gained), but do not appear
on Qualify lists, Class information, or Help files. Secret skills are
never taught by Guildmasters (MOBTeachers) unless specifically told to.
The next parameter is a List of Strings, representing a list of
skills which must be known by this class before he can learn the skill
in question. The last parameter is a String representing a mask which
must be passed by the person who wants to gain this skill.</p>
      <pre>  public CMSecurity.SecGroup getSecurityFlags( int classLevel )<br />  {<br />    if( classLevel &gt; 1000 )<br />    {<br />      CMSecurity.SecFlag[] flags = new CMSecurity.SecFlag[] {<br />      CMSecurity.SecFlag.ABOVELAW,<br />      CMSecurity.SecFlag.LISTADMIN<br />      }<br />      return new CMSecurity.SecGroup(flags);<br />    }<br />    else<br />    {<br />      return new CMSecurity.SecGroup(new CMSecurity.SecFlag[0]);<br />    }<br />  }<br /></pre>
      <p>The purpose of this
method is to allow you to assign CoffeeMud
Security Flags or CoffeeMud Security Groups to your players based on
their Character Class and Character Class Level. This is a rather
obscure feature that is really only meant for special Character Classes
you may design for your admins and builders. Your player <code>getSecurityGroups()</code>
methods will normally just return an empty List regardless of
classLevel. In this case, however, we are demonstrating how a player
who gains 1001 levels in our NormalGuy Class will become immune to the
CoffeeMud legal system (ABOVELAW flag) and gain access to the Archon
LIST command (LISTADMIN flag). See the Archon's Guide for more
information on the CoffeeMud security system.</p>
      <pre>  public boolean qualifiesForThisClass( MOB mob, boolean quiet )<br />  {<br />    if( !CMLib.flags().canBreathe( mob ) )<br />    {<br />      if( !quiet )<br />      {<br />        mob.tell( "You need to be breathing to be a normal guy." );<br />      }<br />      return false;<br />    }<br />    return super.qualifiesForThisClass( mob, quiet );<br /> }<br /></pre>
      <p>The <code>qualifiesForThisClass()</code>
method would actually check and enforce the qualifications described by
      <code>statQualifications()</code>.
In our example above, there is only a check to
see if the idiot is still breathing. Also note that a quiet boolean
exists to allow qualifications to be checked without sending any
messages to the player in question.</p>
      <pre>  private final String[] raceRequiredList=new String[] {<br />    "Human","Humanoid","Troll-kin","Elf"<br />  };<br />  public String[] getRequiredRaceList(){ return raceRequiredList; }<br /><br /></pre>
      <p>The next method, like <span style="font-family: monospace;">qualifiesForThisClass</span><code>&nbsp;</code>method
above is for checking qualifications. It contains an exhaustive list of
all races, race IDs, or racial categories required to become this
class. &nbsp;A list with the word "All" would let any race become
the
class.</p>
      <pre>  private final Pair&lt;String,Integer&gt;[] minimumStatRequirements=new Pair[]{<br />    new Pair&lt;String,Integer&gt;("Strength",Integer.valueOf(9)),<br />    new Pair&lt;String,Integer&gt;("Intelligence",Integer.valueOf(9))<br />  };<br />  public Pair&lt;String,Integer&gt;[] getMinimumStatRequirements() { return minimumStatRequirements; }<br /></pre>
      <p>The next method, like <span style="font-family: monospace;">qualifiesForThisClass</span><code>&nbsp;</code>method
above is for checking qualifications. It contains an exhaustive list
character stat names, and minimum values required to become this class.
&nbsp;An empty list, of course, means no stat requirements.</p>
      <pre>  public String otherBonuses()<br />  {<br />    return "Receives a mortgage, but no home.";<br />  }<br /></pre>
      <p>The next method, like <code>statQualifications
above()</code>,
is for the benefit of the web macros. It describes any special bonuses
received due to being this class.</p>
      <pre>  public List&lt;Item&gt; outfit( MOB myChar )<br />  {<br />    if( outfitChoices == null )<br />    {<br />      outfitChoices = new Vector();<br />      Weapon w = (Weapon)CMClass.getWeapon( "a mortgage" );<br />      outfitChoices.add( w );<br />    }<br />    return outfitChoices;<br />  }<br /></pre>
      <p>The outfit method should
return a&nbsp;List of any
Class-Specific
Item object equipment they may need. Clothing and so forth is actually
covered by Races.</p>
      <pre>  public void grantAbilities( MOB mob, boolean isBorrowedClass )<br />  {<br />    super.grantAbilities( mob, isBorrowedClass );<br />    if( mob.isMonster() )<br />    {<br />      List&lt;AbilityMapper.AbilityMapping&gt; V=CMLib.ableMapper().getUpToLevelListings(ID(), mob.charStats().getClassLevel(ID()), false, false );<br /><br />      for(final AbilityMapper.AbilityMapping able : V)<br />      {<br />        final Ability A=CMClass.getAbility(able.abilityID());<br /> &nbsp;      if( ( A != null )<br />        &amp;&amp; ( ( A.classificationCode()&amp;Ability.ALL_ACODES) != Ability.ACODE_COMMON_SKILL )<br />        &amp;&amp; ( !CMLib.ableMapper().getDefaultGain( ID(), true, A.ID() ) ))<br />        {<br />          giveMobAbility( mob, A, CMLib.ableMapper().getDefaultproficiency( ID(), true, A.ID() ),<br />                        CMLib.ableMapper().getDefaultParm( ID(), true, A.ID() ), isBorrowedClass );<br />        }<br />      }<br />    }<br />  }<br /></pre>
      <p>This important method is
called whenever a player gains a
level in this class, or when an NPC mob is being "outfitted" with this
class via one of the following Behaviors: CombatAbilities, Fighterness,
Druidness, Bardness, Clericness, Thiefness, Mageness.</p>
      <p>The <code>grantAbilities()</code>
method has the important
job of making sure that players receive their autogained skills or any
other options skills when they level. The StdCharClass version of
grantAbilities (called by <code>super.grantAbilities(...)</code>)
takes care of any autogained skills up to the player or mobs current
level in the class. Each char class which extends this, however, needs
to take care of any skills or abilities for NPC mobs which are not
automaticallyy gained. This is to make up for the fact that npc mobs
will not be lining up at your guildmasters to spend their trains on
skills they merely qualify for. In the sample code above, we give the
mobs every skill the class qualifies for up to the mobs level in the
class, except for any common skills. Those would still need to be given
by hand to each mob.</p>
      <pre>  public boolean okMessage( Environmental myHost, CMMsg msg )<br />  {<br />    if( !( myHost instanceof MOB ) )<br />    {<br />      return super.okMessage( myHost, msg );<br />    }<br /><br />    MOB myChar = (MOB)myHost;<br /><br />    if( ( msg.amITarget( myChar ) )<br />    &amp;&amp;( msg.targetMinor() == CMMsg.TYP_DAMAGE )<br />    &amp;&amp;( ( msg.sourceMinor() == CMMsg.TYP_COLD )<br />    ||( msg.sourceMinor() == CMMsg.TYP_WATER )))<br />    {<br />      int recovery = myChar.charStats().getClassLevel( this );<br />      msg.setValue( msg.value() - recovery );<br />    }<br />    else <br />    if( ( msg.amITarget( myChar ) )<br />    &amp;&amp;( msg.targetMinor() == CMMsg.TYP_DAMAGE )<br />    &amp;&amp;( msg.sourceMinor() == CMMsg.TYP_FIRE ))<br />    {<br />      int recovery = msg.value();<br />      msg.setValue( msg.value() + recovery );<br />    }<br /><br />    return super.okMessage( myChar, msg );<br />  }<br />}<br /></pre>
      <p>And lastly, just as I'm
sure you were wondering how useful
those three Core Topics above would really be, we see them in active
use. Some classes contain methods such as these to enforce some of the
benefits for the class. In the <code>okMessage()</code>
method, which
we discussed in the first Core Topic, we see messages messages
containing the type of damage taken by the player being intercepted.
TYP_DAMAGE messages always have their damage amounts stored in the <code>.value()</code>
method of a message, so it is these values which are modified, based on
the type of damage taken.</p>
      <p>And not least, although
we won't go into it in detail here,
there are two other methods which may be of use for the advanced
Character Class programmer. They are the level and unLevel methods.
These methods are called when a player gains or loses (respectively) a
level in the class. If there are any extra skills or bonus scores the
player may wish to gain and lose with levels, that would be the place
for such code. Also, in some cases (Mages and Clerics come to mind),
the gaining of qualifying skills may be somewhat complex. In those
cases, overriding the gainAbilities method may be in order. Check the
Mage and Cleric classes for more information.</p>
      <img src="images/dragon.jpg" alt="Races" />
      <h2><a name="RACES" id="RACES">Races</a></h2>
      <p>A Race, in CoffeeMud,
contributes very little to
functionality, but quite a bit to the role playing and other "soft"
aspects of the game.. For this reason, everyone is encouraged to code
as many races as humanly possible. The more, the better! Races import
the same packages mentioned in the first section of this document under
Complete Default Import List as well as (in this case)
com.planet_ink.coffee_mud.Races.StdRace because our sample class
extends it. Your custom races need to be listed in your coffeemud.ini
file under the RACES entry. Aside from making custom race classes, you
can also extend an existing race class, return an identical ID()
string, and then list it at the end of the aforementioned entry in the
coffeemud.ini file. Now, let's take a look at a simple one here:</p>
      <pre>public class Grumbler extends com.planet_ink.coffee_mud.Races.StdRace<br />{<br /></pre>
      <p>Our Grumbler race will
define all of the basic elements of a
filled-out race.</p>
      <pre>  public String ID()<br />  {<br />    return "Grumbler";<br />  }<br /><br />  public String name()<br />  {<br />    return "Grumbler";<br />  }<br /><br />  public String racialCategory()<br />  {<br />    return "Grumbler";<br />  }<br /><br />  protected static Vector&lt;RawMaterial&gt; resources = new Vector&lt;RawMaterial&gt;();<br /><br />  public int availabilityCode()<br />  {<br />    return Area.THEME_FANTASY;<br />  }<br /></pre>
      <p>The first methods return
the unique ID of the Race (which must
always match the java/class file name) and the <code>name()</code>
method is the displayable name of the Race. The third method is very
important, as it defines the category into which this race falls. There
is no hard rule to determine when a new category should be created
versus using an old one. Some of the uses of racial categories include
the Ranger Favored Enemy skill, as well as most of the race-based
restrictions on doors and with shopkeepers. In many ways, the racial
category is more important than the name of the race itself, if
functionality is considered.</p>
      <p>The last method list
above, availabilityCode, defines how
players can access this race. Possible values for this constant
include: 'Area.THEME_FANTASY' (makes the race available for players to
choose when creating fantasy characters),
'Area.THEME_FANTASY|Area.THEME_SKILLONLYMASK' (makes the race available
to spells such as Polymorph or Wish, but not for player creation), or
'0' (the race is not available to spells or for player creation.)</p>
      <p><span style="font-family: monospace;">&nbsp; public
int[]
getBreathables() { return new int[]{ RawMaterial.RESOURCE_AIR }; }</span><br />
      </p>
      <p>This method returns
either an empty array, or an array of
integers, each of which is a RawMaterial code representing something
like AIR, or FRESHWATER, or OXYGEN, etc. It tells the system what kind
of atmospheres this race can breathe without dying. &nbsp;There are
several pre-defined built-in static arrays in StdRace.java that you can
use for common cases, such as&nbsp; <span
 style="font-family: monospace;">breatheAirArray</span>, <span
 style="font-family: monospace;">breatheWaterArray</span>, <span
 style="font-family: monospace;">breatheAirWaterArray</span>,
or <span style="font-family: monospace;">breatheAnythingArray</span>
(which is
empty). &nbsp;You can define your own also, of course.
&nbsp;Remember
that the RawMaterial codes you return will be the ONLY atmospheres the
race can breathe. &nbsp;Returning an empty integer array int[0]
will
denote that the race can breathe anything.</p>
      <pre>  public int shortestMale()<br />  {<br />    return 84;<br />  }<br /><br />  public int shortestFemale()<br />  {<br />    return 78;<br />  }<br /><br />  public int heightVariance()<br />  {<br />    return 80;<br />  }<br /><br />  public int lightestWeight()<br />  {<br />    return 2000;<br />  }<br /><br />  public int weightVariance()<br />  {<br />    return 500;<br />  }<br /></pre>
      <p>These methods, as you
might have guessed, establish parameters
for the base height and weight of a typical monster of this type. A
random number from 0-<code>heightVariance()</code>
will be added to the <code>shortedMale()</code>/<code>shortestFemale()</code>
value to
determine height, while a random number from 0-<code>weightVariance()</code>
will be added to <code>lightestWeight()</code>
to determine that.</p>
      <pre>  public long forbiddenWornBits()<br />  {<br />    return Wearable.WORN_WIELD<br />          |Wearable.WORN_WAIST<br />          |Wearable.WORN_ABOUT_BODY<br />          |Wearable.WORN_FEET<br />          |Wearable.WORN_HANDS;<br />  }<br /></pre>
      <p>This method establishes
where a creature of this type may NOT
wear something. In this case, we forbid any wielded items, or anything
worn around the waist, on hands or feet, or about the body. Anywhere
else is fine. Return 0 if you do not wish any restrictions on wearing.</p>
      <pre>  private static final int[] parts = {0,2,2,1,1,0,0,1,4,4,1,0,1,1,1,2};<br /><br />  public int[] bodyMask()<br />  {<br />    return parts;<br />  }<br /></pre>
      <p>The <code>bodyMask()</code>
method defines and returns an
array of integers which defines the types and number of particular body
parts normally retained by the race. Each position in the array is
defined by the equates BODY_ in the Race interface. These equates are
(starting from 0): BODY_ANTENEA, BODY_EYE, BODY_EAR, BODY_HEAD,
BODY_NECK, BODY_ARM, BODY_HAND, BODY_TORSO, BODY_LEG, BODY_FOOT,
BODY_NOSE, BODY_GILL, BODY_MOUTH, BODY_WAIST, BODY_TAIL, BODY_WING.
Remember that these can be found in the Race interface for you to
reference. In the above example, we find no antenea, 2 eyes, 2 ears, a
head, neck, no arms or hands, a torso, 4 legs, 4 feet, a nose, but no
gill, and then a mouth, waist, tail, and 2 wings.</p>
      <pre>  private String[] racialAbilityNames = { "Skill_Trip", "Fighter_Whomp" };<br />  private int[] racialAbilityLevels = { 1, 3 };<br />  private int[] racialAbilityProficiencies = { 75, 50 };<br />  private boolean[] racialAbilityQuals = { false, false };<br /><br />  protected String[] racialAbilityNames()<br />  {<br />    return null;<br />  }<br /><br />  protected int[] racialAbilityLevels()<br />  {<br />    return null;<br />  }<br /><br />  protected int[] racialAbilityProficiencies()<br />  {<br />    return null;<br />  }<br /><br />  protected boolean[] racialAbilityQuals()<br />  {<br />    return null;<br />  }<br /><br />  public List&lt;Ability&gt; racialAbilities( MOB mob )<br />  {<br />    List V = super.racialAbilities( mob );<br />    return V;<br />  }<br /></pre>
      <p>Our next section here
deals with Racial Abilities, which are
defined as follows: A racial ability is a skill that has a command
word, and is not autoinvoked. A racial ability may be qualified for or
automaticallyy gained. If the skill is qualified for, then upon
reaching the designated player level, the player may GAIN the skill,
and will have a default proficiency as designated. If the skill is not
qualified for, then it is automaticallyy gained. This means that all
mobs or players of this race, who have obtained the necessary player
level, will have access to the use of the skill as if they had learned
it, and at the proficiency designated. Racial Abilities are available
to any mob or player of this race, even those affected by Shape Shift,
Polymorph, or similar skills.</p>
      <p>The first four methods
define these skills. The data in all
four variables are ordered with relative to each other. The <code>racialAbilityNames</code>
is a list of the Ability class ID. The <code>racialAbilityLevels</code>
is the level at which the skill is qualified for or gained. The <code>racialAbilityProficiencies()</code>
is the proficiency of skills automaticallyy gained. The <code>racialAbilityQuals()</code>
tells whether or not the skill is automaticallyy gained (false) or is
only qualified for (true).</p>
      <p>The method above (<code>racialAbilities()</code>)
will return
a&nbsp;List of Ability objects, with proficiency already set,
appropriate
to the mob passed in. This list should consist only of automaticallyy
gained abilities appropriate to the level of the mob. If the four
variables are set properly, the programmer will not need to override
the method from StdRace unless there other gender-based or other
special qualifications for skills not defined by those four variables.</p>
      <pre>  public List&lt;Item&gt; outfit( MOB myChar )<br />  {<br />    if( outfitChoices == null )<br />    {<br />      outfitChoices = new Vector();<br />      Weapon w = (Weapon)CMClass.getItem( "GenPants" );<br />      outfitChoices.add( w );<br />    }<br />    return outfitChoices;<br />  }<br /></pre>
      <p>The outfit method should
return a&nbsp;List of any
Race-Specific
Item object equipment they may need.</p>
      <pre>  private String[] culturalAbilityNames = { "Dwarven", "Mining" };<br />  private int[] culturalAbilityProficiencies = { 100, 50 };<br /><br />  public String[] culturalAbilityNames()<br />  {<br />    return culturalAbilityNames;<br />  }<br /><br />  public int[] culturalAbilityProficiencies()<br />  {<br />    return culturalAbilityProficiencies;<br />  }<br /></pre>
      <p>Cultural Abilities are
defined as those skills which a mob or
player of this race would know through upbringing in the culture of
that race, such as language. Players Shape Shifted or Polymorphed into
the race, since they did not grow up in the culture, would not have
automatic access to these skills per se. These two methods are defined
similarly to the Racial Abilities above.</p>
      <pre>  public void affectPhyStats( Physical affected, PhyStats affectableStats )<br />  {<br />    super.affectPhyStats( affected, affectableStats );<br /><br />    affectableStats.setSensesMask(affectableStats.sensesMask() | PhyStats.CAN_SEE_INFRARED);<br />  }<br /></pre>
      <p>This sample of the <code>affectPhyStats()</code>
method we
discussed in the Core Topics above makes sure that all creatures of
this race can see in the infrared spectrum.</p>
      <pre>  public void affectCharStats( MOB affectedMOB, CharStats affectableStats )<br />  {<br />    super.affectCharStats( affectedMOB, affectableStats );<br />    affectableStats.setStat( CharStats.STAT_STRENGTH, 15 );<br />    affectableStats.setStat( CharStats.STAT_DEXTERITY, 25 );<br />    affectableStats.setStat( CharStats.STAT_INTELLIGENCE, 5 );<br />  }<br /></pre>
      <p>This sample of the
affectCharStats method we discussed in the
Core Topics above establishes a base strength, dexterity, and
intelligence for all creatures of this race. As this is the ONLY way to
modify a MOBs stats short of magical equipment, it should be used with
care!</p>
      <pre>  public void startRacing( MOB mob, boolean verifyOnly )<br />  {<br />    super.startRacing( mob, verifyOnly );<br />  }<br /></pre>
      <p>startRacing is called
whenever a player of this race logs on,
or a mob of this race is created. If there are any special properties
of the mob or player which must be set due to their being this race,
this would be the appropriate method in which to do so. This method is
not called for Polymorph, Shape Shift, or similar changes in race, but
only for those whose permanent race is this one.</p>
      <pre>  public Weapon myNaturalWeapon()<br />  {<br />    if( naturalWeapon == null )<br />    {<br />      naturalWeapon = CMClass.getWeapon( "StdWeapon" );<br />      naturalWeapon.setName( "huge claws" );<br />      naturalWeapon.setMaterial(RawMaterial.RESOURCE_BONE);<br />      naturalWeapon.setUsesRemaining(1000);<br />      naturalWeapon.setWeaponDamageType( Weapon.TYPE_PIERCING );<br />    }<br />    return naturalWeapon;<br />  }<br /></pre>
      <p>This method allows you to
create (see item creation above) a
special weapon to serve the creature whenever they are not wielding
something. Since our Grumbler cannot wield weapons anyway, it is
important to give them some big piercing claws.</p>
      <pre>  public String healthText( MOB viewer, MOB mob )<br />  {<br />    double pct = ( CMath.div( mob.curState().getHitPoints(), mob.maxState().getHitPoints() ) );<br />    if( pct &lt; .10 )<br />    {<br />      return "^r" + mob.displayName(viewer) + "^ris raging in bloody pain!^N";<br />    }<br />    else <br />    if( pct &lt; .20 )<br />    {<br />      return "^r" + mob.displayName(viewer) + "^ris covered in blood.^N";<br />    }<br />    else if( pct &lt; .30 )<br />    {<br />      return "^r" + mob.displayName(viewer) + "^r is bleeding badly from lots of wounds.^N";<br />    }<br />    else if( pct &lt; .50 )<br />    {<br />      return "^y" + mob.displayName(viewer) + "^y has some bloody wounds and gashed scales.^N";<br />    }<br />    else if( pct &lt; .60 )<br />    {<br />      return "^p" + mob.displayName(viewer) + "^p has a few bloody wounds.^N";<br />    }<br />    else if( pct &lt; .70 )<br />    {<br />      return "^p" + mob.displayName(viewer) + "^p is cut and bruised heavily.^N";<br />    }<br />    else if( pct &lt; .90 )<br />    {<br />      return "^g" + mob.displayName(viewer) + "^g has a few bruises and scratched scales.^N";<br />    }<br />    else if( pct &lt; .99 )<br />    {<br />      return "^g" + mob.displayName(viewer) + "^g has a few small bruises.^N";<br />    }<br />    else<br />    {<br />      return "^c" + mob.displayName(viewer) + "^c is in perfect health.^N";\<br />    }<br />  }<br /></pre>
      <p>Although the programmer
is welcome to skip the above method
and use the defaults from the StdRace class, this allows you to set
special health messages for creatures of this type.</p>
      <pre>  public List&lt;RawMaterial&gt; myResources()<br />  {<br />    synchronized( resources )<br />    {<br />      if( resources.size() == 0 )<br />      {<br />        resources.addElement( makeResource( "a " + name().toLowerCase() + "claw",  RawMaterial.RESOURCE_BONE ) );<br /><br />        for( int i = 0; i &lt; 10; i++ )<br />        {<br />          resources.addElement( makeResource( "a strip of " + name().toLowerCase() + " hide", RawMaterial.RESOURCE_SCALES) );<br />        }<br /><br />        for( int i = 0; i &lt; 10; i++ )<br />        {<br />          resources.addElement( makeResource( "a pound of " + name().toLowerCase() + " meat", RawMaterial.RESOURCE_MEAT ));<br />        }<br /><br />        resources.addElement( makeResource( "some " + name().toLowerCase() + " blood", RawMaterial.RESOURCE_BLOOD));<br />      }<br />    }<br />    return resources;<br />  }<br />}<br /></pre>
      <p>The above method allows
you to determine what sorts of
materials are gotten from this creature whenever the dead corpse is
Butchered.</p>
      <p>Now, in addition to the
methods above which are good to
include in your custom races, there are also several methods which are
not normally extended or overridden, but which is may be good to do so
in special cases. These methods include <code>public
void level( MOB
mob )</code>, which is called
whenever a player of that race gains a
level, public void <code>agingAffects(
MOB mob, CharStats baseStats,
CharStats charStats )</code> , which
is called to enforce how aging
effects this race, and <code>public
DeadBody getCorpseContainer( MOB
mob, Room room )</code>, which is
called to create a corpse for members
of this race.</p>
      <img src="images/chomper.jpg" alt="Exits" />
      <h2><a name="EXITS" id="EXITS">Exits</a></h2>
      <p>Exits are the connecting
points between two rooms, and tend to
be rather simple. If two rooms, A &amp; B, are connected to each
other,
there are always two exits associated with that connection. One from
room A to room B, and the other from room B to room A.</p>
      <p>Exits import the same
packages mentioned in the first section
of this document under Complete Default Import List as well as (in this
case) com.planet_ink.coffee_mud.Exits.StdExit because our sample class
extends it. Here is an example exit:</p>
      <pre>public class SlidingDoor extends com.planet_ink.coffee_mud.Exits.StdExit<br />{<br />  public String ID()<br />  {<br />    return "SlidingDoor";<br />  }<br /><br />  public SlidingDoor()<br />  {<br />    super();<br />    Ability A = CMClass.getAbility( "Prop_ReqHeight" );<br />    A.setMiscText( "30" );<br />    addNonUninvokableEffect( A );<br />  }<br /><br />  public String name()<br />  {<br />    return "a sliding door";<br />  }<br /><br />  public String displayText()<br />  {<br />    return "";<br />  }<br /><br />  public String closedText()<br />  {<br />    return "a closed sliding door";<br />  }<br /><br />  public String doorName()<br />  {<br />    return "door";<br />  }<br /><br />  public String openName()<br />  {<br />    return "slide";<br />  }<br /><br />  public String closeName()<br />  {<br />    return "slide";<br />  }<br /><br />  public boolean hasADoor()<br />  {<br />    return true;<br />  }<br /><br />  public boolean hasALock()<br />  {<br />    return false;<br />  }<br /><br />  public boolean defaultsLocked()<br />  {<br />    return false;<br />  }<br /><br />  public boolean defaultsClosed()<br />  {<br />    return true;<br />  }<br /><br />  public int openDelayTicks()<br />  {<br />    return 45;<br />  }<br />}<br /></pre>
      <p>As you can see, exits are
very simple. A set of variables and
parameters are sufficient to establish every function of an exit, and
these are already well defined in the Archon's Guide. This is due
primarily to the fact that several Properties and Behaviors give an
exit most of its color and complexity.</p>
      <p>Exits, like all other
Environmental objects, get to preview
and execute messages. They will only tend to listen for messages
dealing with OPENING or CLOSING where the exit is the target, or
ENTERING and LEAVING where the exit is the tool. If a player is going
from room A to room B. The player message will note that he or she is
ENTERING the exit in room A and LEAVING the exit in room B. Although
this makes perfect sense to me, it may sound a little backwards from
the intuitive way. Since Room objects (Locales) are almost always the
target of ENTER and LEAVE messages, exits are subordinated to being the
tools of such messages.</p>
      <p>Exits will never tick, by
and large, unless they have a door
that defaults closed and the door is opened, or they gain some sort of
Behavior (such as Emoter).</p>
      <img src="images/scenery.jpg" alt="Locales" />
      <h2><a name="LOCALES" id="LOCALES">Locales</a></h2>
      <p>Locales are the stuff
rooms are made of, and so they implement
the interface Room. There are actually four different general types of
locales: the standard room, the standard grid, the "thin" grid, and the
standard maze. Each of those respectively is a functional superset of
the former respectively. Rooms import the same packages mentioned in
the first section of this document under Complete Default Import List
as well as (in this case) com.planet_ink.coffee_mud.Rooms.StdGrid,
com.planet_ink.coffee_mud.Rooms.StdRoom, or
com.planet_ink.coffee_mud.Rooms.StdMaze, because our sample classes
extends them.</p>
      <p>Let's looks at an example
of a standard grid room, which has
much of the functionality we are interested in:</p>
      <pre>public class RoadGrid extends com.planet_ink.coffee_mud.Locales.StdGrid<br />{<br />  public String ID()<br />  {<br />    return "RoadGrid";<br />  }<br /><br />  public RoadGrid()<br />  {<br />    super();<br />    name = "a road";<br />    basePhyStats.setWeight( 1 );<br />    recoverPhyStats();<br />  }<br /><br />  public String getGridChildLocaleID()<br />  {<br />    return "Road";<br />  }<br /><br />  public List&lt;Integer&gt; resourceChoices()<br />  {<br />    return Road.roomResources;<br />  }<br /><br />  public int domainType()<br />  {<br />    return Room.DOMAIN_OUTDOORS_PLAINS;<br />  }<br />}<br /></pre>
      <p>Here we see the standard
RoadGrid. It's effects, behaviors,
displaytext, description, and (since it is a grid type) size in the x
and y are all defined by the builder. The features (and they aren't
many) which are available to the coder can be seen here. We see the
base weight being set to "1" here. This is the default number of
movement points consumed by crossing this room. For Grids, we see the
Locale ID of the child-rooms inside the grid. We also see the standard
room settings methods for the domain type (the type of locale it is)
and the domain conditions (the quality of the weather, or the air,
wetness, dryness, etc).</p>
      <p>The Resource choices for
this room are borrowed from the Road
itself, though this will never be used. Players will never actually be
inside the Grid room itself, but will always occupy one of the child
rooms, each of which will take direction from the parent Grid. If you
wish to define resources, however, be aware that the resourceChoices
list returned may not be null, and must only contain Integer objects
representing the Resource (see the Items.interfaces.RawMaterial.java
interface) available there. Use the RESOURCE_* static integer values
from RawMaterial interface.</p>
      <p>Here are another set of
useful methods:</p>
      <pre> public String displayText(MOB mob)<br /> public String description(MOB mob)<br /></pre>
      <p>These methods return the
title and description of the room
respectively. These methods are responsible for making the title and
description into a proper displayable format. They draw on the values
of the room object <code>displayText()</code>
and <code>description()</code>
methods respectively, then parse that data for any special display
codes, though often that data is simply passed through.</p>
      <p>The <code>executeMsg()</code>,
and <code>okMessage()</code>
methods on rooms are also available, as they are in all Environmental
objects, for customized message handling as described in the Core
Topics above.</p>
      <img src="images/area.jpg" alt="Areas" />
      <h2><a name="AREAS" id="AREAS">Areas</a></h2>
      <p>The Area objects, which
represent areas in the game, are the
most difficult to advise about regarding programming.</p>
      <p>However, an attempt must
be made. Therefore, we will go over
some of the methods and features available on the Area object, which
might be overridden for some other use. Areas import the same packages
mentioned in the first section of this document under Complete Default
Import List.</p>
      <pre>public class StdArea implements Area<br />{<br />  public String ID()<br />  {<br />    return "StdArea";<br />  }<br /><br /> [...]<br /><br />  public Climate getClimateObj(){...}<br />  public int climateType(){...}<br />  public void setClimateType( int newClimateType ){...}<br /></pre>
      <p>Of course, like every
Environmental object, the Area must
define an <code>ID()</code>.
Notice that the <code>ID()</code>
is the same as the name of the class. This is no accident -- this is
required! The name, display text, description, and others are all
handled by the builder, or Properties or behaviors, and aren't
pertinent to this discussion of Areas.</p>
      <p>The weather, however, is
a relative function of each area.
Each area knows its current weather object (see the Climate interface)
as well as the next weather change "in the que". These can be read and
set by the methods in the Climate object. Each area also knows it
climatic "tendencies", and this also can be set and read from the area
itself. Lastly, a method exists on the Climate object to force the area
to cycle through its weather, which will force the "next" weather code
to become current, and establish a new "next" weather code.</p>
      <pre>  public int getTheme()<br />  public void setTheme( int level )<br /></pre>
      <p>These will return the
technical level allowed in the area,
whether it be magic, technology, or both.</p>
      <pre>  public String getArchivePath()<br />  public void setArchivePath( String pathFile )<br /></pre>
      <p>The Archive name of the
area is set and read from the area,
though it's more properly set by the builder.</p>
      <pre>  public TimeClock getTimeObj()<br /></pre>
      <p>Similar to Climate above,
each area has a reference to a
TimeClock object which contains information about local time. Unlike
the Climate, however, StdAreas all share the same Time object, meaning
that time is global. However, the object exists here in case you want
local time areas.</p>
      <pre>  public void toggleMobility( boolean onoff )<br />  public boolean getMobility()<br /></pre>
      <p>These methods define
whether Mobile mobs will move around. By
toggling mobility off, no mob or player in the whole area will move
from room to room for any reason, allowing a good base state for
builders to work from.</p>
      <pre>  public StringBuffer getAreaStats()<br /></pre>
      <p>If the data, appearance,
or format of the HELP provided for
areas needs to be changed, the <code>getAreaStats()</code>
method is
where to generate a new one.</p>
      <pre>  public Enumeration&lt;Room&gt; getMetroMap()<br />  public int metroSize()<br />  public Room getRandomMetroRoom()<br /></pre>
      <p>These methods provide
access to all of the rooms in the given
area, plus all of the rooms in any child areas, plus any rooms in their
children areas and so forth.</p>
      <pre>  public void fillInAreaRooms()<br />  public void fillInAreaRoom( Room R )<br /><br />  public Enumeration&lt;Room&gt; getProperMap()<br />  public int properSize()<br />  public Room getRandomProperRoom()<br />  public void clearMetroCache()<br /></pre>
      <p>The first two methods are
called in order to perform
finalizing clean-up or resetting of room structures. The remaining
methods provide access to the set of rooms which are directly a part of
this area. The last method is one which should be called if any proper
rooms are ever added, since it clears and "re-calculates" the metro
rooms list.</p>
      <pre>  public void addSubOp( String username )<br />  public void delSubOp( String username )<br />  public boolean amISubOp( String username )<br />  public String getSubOpList()<br />  public void setSubOpList( String list )<br /></pre>
      <p>And lastly, the list of
staff (Area Archons they are also
sometimes called), can be managed from here. Changing these methods
would modify how staff are handled by Areas.</p>
      <img src="images/house.jpg" alt="Properties" />
      <h2><a name="PROPS" id="PROPS">Properties</a></h2>
      <p>Properties are the
simplest of the objects which implement the
Ability interface, and are defined as effects which can be permanently
tacked-on to items, mobs, and other Physical objects. Properties
are Abilities, but they are never qualified for by classes, never
gained as skills, and never wear off or disappear when a mob dies. They
are always added to a mob, item, room, etc using the Physical
interface method <code>addNonUninvokableEffect(
Ability )</code>
method either inside a custom coded Physical object, or at
run-time to a GenMob, GenItem, Room, or similar type object.</p>
      <p>Properties and Behaviors
are often the basic building blocks
of the customized GenMob and GenItem in CoffeeMud, and differ from each
other in this basic respect: Properties tend to have a smaller memory
footprint and tend to react to events affecting their hosts rather than
cause their hosts to take proactive actions. Properties make heavy use
of the message handlers and stat affecting methods. If you have not
read the Core Topics above already, you should do so now.</p>
      <p>A Custom property may or
may not belong to any particular
package, though it is important that the ID() of the property be unique
in the system. Properties import the same packages mentioned in the
first section of this document under Complete Default Import List as
well as (in this case) com.planet_ink.coffee_mud.Properties.Property
because our sample class extends it.</p>
      <p>A customized property
class must extend the Property class
implemented in the aforementioned package. This Property class already
implements the Ability interface, and already has dummy methods for
most of the Ability interface methods which are unnecessary or are
unused in a Property.</p>
      <p>Each property must also
have custom <code>ID()</code>,
and <code>name()</code>
methods as shown below. Notice that the <code>ID()</code>
is the same
as the name of the class. This is no accident -- this is required!</p>
      <pre>public class Prop_AstralSpirit extends com.planet_ink.coffee_mud.Abilities.Properties.Property<br />{<br />  public String ID()<br />  {<br />    return "Prop_AstralSpirit";<br />  }<br /><br />  public String name()<br />  {<br />    return "Astral Spirit";<br />  }<br /></pre>
      <p>Above we see the
aforementioned methods defined. The Property
does not differ from other Abilities, or indeed other Physical
objects in this respect. A unique <code>ID()</code>,
and <code>name()</code>
method must be defined for each new class.</p>
      <pre>  protected int canAffectCode()<br />  {<br />    return Ability.CAN_MOBS;<br />  }<br /><br />  public String accountForYourself()<br />  {<br />    return "an astral spirit";<br />  }<br /></pre>
      <p>Here are two important
support methods you will also find in
Skills and the other more standard Abilities. The first method tells
what type of objects (Areas, MOBs, Items, Rooms, or Exits) can be
affected by this property. In this case, this property only affects
MOBS. A value like Ability.CAN_MOBS|Ability.CAN_ITEMS would denote one
that affects MOBs or Items.</p>
      <p>The second method is a
string which is returned whenever this
property appears on an Item which is Identified. This string would
appear in addition to any secretIdentity defined for the item.</p>
      <pre>  /** this method defines how this thing responds<br />  * to environmental changes. It may handle any<br />  * and every msg listed in the CMMsg class<br />  * from the given Environmental source */<br />  public boolean okMessage( Environmental myHost, CMMsg msg )<br />  {<br />    if( ( affected == null ) || ( !( affected instanceof MOB ) ) )<br />    {<br />      return true;<br />    }<br /><br />    MOB mob = (MOB)affected;<br /><br />    if( ( msg.amISource( mob ) )<br />    &amp;&amp; ( !CMath.bset( msg.sourceMajor(), CMMsg.MASK_ALWAYS ) ))<br />    {<br />      if( ( msg.tool() != null )<br />      &amp;&amp;( msg.tool().ID().equalsIgnoreCase( "Skill_Revoke" ) ))<br />      {<br />        return super.okMessage( myHost, msg );<br />      }<br />      else if( msg.targetMinor() == CMMsg.TYP_WEAPONATTACK )<br />      {<br />        mob.tell( "You are unable to attack in this incorporeal form." );<br />        peaceAt( mob );<br />        return false;<br />      }<br />      else if( ( CMath.bset( msg.sourceMajor(), CMMsg.MASK_HANDS ) )<br />      || ( CMath.bset( msg.sourceMajor(), CMMsg.MASK_MOUTH ) ))<br />      {<br />        if( CMath.bset( msg.sourceMajor(), CMMsg.MASK_SOUND ) )<br />        {<br />          mob.tell( "You are unable to make sounds in this incorporeal form." );<br />        }<br />        else<br />        {<br />          mob.tell( "You are unable to do that this incorporeal form." );<br />        }<br /><br />        peaceAt( mob );<br />        return false;<br />      }<br />    }<br />    else <br />    if( ( msg.amITarget( mob ) )<br />    &amp;&amp;( !msg.amISource( mob ) )<br />    &amp;&amp;( !CMath.bset( msg.targetMajor(), CMMsg.MASK_ALWAYS ) ))<br />    {<br />      mob.tell( mob.name() + " doesn't seem to be here." );<br />      return false;<br />    }<br /><br />    return true;<br />  }<br /></pre>
      <p>As discussed in the Core
Topics above, here is an example of
an okMessage method. In this case, we intercept attack and other vocal
or hand movement messages where the source of the action is the mob
whose property this is. We then return false, effectively canceling
those messages, after telling the poor bloke why we are doing it. The
rest of the method prevents any messages from targeting the mob with
this property. This saves him from being attacked by aggressives, or
arrested by cityguards -- since technically he isn't even there.</p>
      <pre>  public void affectPhyStats( Physical affected, PhyStats affectableStats )<br />  {<br />    super.affectPhyStats( affected, affectableStats );<br />    // when this spell is on a MOBs Affected list,<br />    // it should consistantly put the mob into<br />    // a sleeping state, so that nothing they do<br />    // can get them out of it.<br /><br />    affectableStats.setWeight( 0 );<br />    affectableStats.setHeight( -1 );<br /><br />    affectableStats.setDisposition(<br />    affectableStats.disposition()|PhyStats.IS_GOLEM);<br /><br />    affectableStats.setDisposition(affectableStats.disposition()|PhyStats.IS_INVISIBLE);<br /><br />    affectableStats.setDisposition(affectableStats.disposition()|PhyStats.IS_NOT_SEEN);<br /><br />    affectableStats.setSensesMask(affectableStats.sensesMask()|PhyStats.CAN_NOT_SPEAK);<br />  }<br />}<br /></pre>
      <p>Last but not least, here
is another example from the Core
Topics, an <code>affectPhyStats()</code>
method. This method will always have the host mob passed in the
"affected" parameter, and a copy of his current PhyStats objects in the
affectableStats parameter. This method then sets the mob as being both
invisible, and totally unseen. It makes him unviewable to infrared, and
prevents him from speaking. The two methods above then combine to
produce our desired results, an Astral Spirit.</p>
      <img src="images/monk.jpg" alt="Skills" />
      <h2><a name="SKILLS" id="SKILLS">Introduction to
Skill Abilities</a></h2>
      <p>Abilities are easily the
most complicated and varied of all
the objects in CoffeeMud. They encompass everything from invoked skills
and spell, like TRIP or MAGIC MISSILE, to natural abilities, like
NONDETECTION. A Skill Ability then is an object which implements the
Ability interface fully, unlike the Property above, which implements
only certain parts.</p>
      <p>An Ability is known in
the mud as any of the following: A
Spell, Song, Dance, Skill, Common Skill, Thief Skill, Poison, Disease,
Prayer, Chant, or Trap. They all implement the Ability interface, which
in turn extends the Environmental interface discussed throughout the
rest of this document. Abilities make extensive use of the okMessage
and executeMsg, tick, and stat affecting methods discussed above in the
Core Topics. If you have not read the Core Topics, you should do so now.</p>
      <p>Abilities will all tend
to extend the basic StdAbility class
found in the Abilities package, and sometimes they will further extend
a class more specific to their type, such as Spell, StdSkill, Song,
BardSkill, Prayer, FighterSkill, ThiefSkill, Chant, or some other basic
types found in the standard CoffeeMud distribution packages.</p>
      <p>Abilities are added to
mob objects using the addAbility method
on MOBs. From there, through casting or by autoInvocation (discussed
below), they may end up in the effects list of a mob, item, room, area,
or exit via the addEffect method.</p>
      <p>A Custom ability may or
may not belong to any particular
package, though it is important that the <code>ID()</code>
of the ability be unique in the system. A custom ability imports the
same packages mentioned in the first section of this document under
Complete Default Import List as well as (in this case)
com.planet_ink.coffee_mud.Abilities.StdAbility because our sample class
extends it.</p>
      <p>A customized ability
class usually extends the StdAbility
class implemented in the aforementioned package. This StdAbility class
already implements the Ability interface, and already has numerous
support methods which aid in the creation of custom abilities.</p>
      <p>Each ability must also
have custom <code>ID()</code>
and <code>name()</code>
methods as shown below. Notice that the <code>ID()</code>
is the same
as the name of the class. This is no accident -- this is required!</p>
      <pre>public class Skill_Trip extends com.planet_ink.coffee_mud.Abilities.StdAbility<br />{<br />  public String ID()<br />  {<br />    return "Skill_Trip";<br />  }<br /><br />  public String name()<br />  {<br />    return "Trip";<br />  }<br /></pre>
      <p>Above we see the
aforementioned methods defined. This skill
does not differ from other Abilities, or indeed other Environmental
objects in this respect. A unique <code>ID()</code>
and <code>name()</code>
method must be defined for each new class.</p>
      <pre>  public String displayText()<br />  {<br />    return "(Tripped)";<br />  }<br /></pre>
      <p>The display text on an
Ability always refers to the text shown
in the "You are affected by" section shown by the SCORE and AFFECTS
commands in the MUD. In this case, someone affected by trip will see
(Tripped). If this method does not leave any information for those
affected by it, it should return "".</p>
      <pre>  protected int canAffectCode()<br />  {<br />    return CAN_MOBS;<br />  }<br /><br />  protected int canTargetCode()<br />  {<br />    return CAN_MOBS;<br />  }<br /></pre>
      <p>These two methods assist
the MUDGrinder, and the HELP files in
classifying the several skills and spells.</p>
      <p>The first method, <code>canAffectCode()</code>,
returns what
type of objects, if any, this ability class may find itself in the
effects list of. Since our Trip skill effects the tripped mob, we list
mobs. Other possible values include any combination of CAN_ROOMS,
CAN_EXITS, CAN_ITEMS, or CAN_AREAS. If a skill may Effect more than
one, they can be combined using the | operator. An example skill that
affects both mobs and items might return CAN_MOBS|CAN_ITEMS, for
instance.</p>
      <p>The second method, <code>canTargetCode()</code>,
above tells
the system what type of objects can be targeted by this skill. Some
skills will target items (like the Enchant Weapon spell), or rooms
(like the Darkness spell), or exits (like the Knock spell). In a
similar fashion to canAffectCode, this method can return any
combination of valid objects to notify the system of proper targets.</p>
      <pre>  public int abstractQuality()<br />  {<br />    return Ability.QUALITY_MALICIOUS;<br />  }<br /></pre>
      <p>This MOST important
method tells the system quite a bit about
the nature of the skill, as well as how mobs with behaviors like
CombatAbilities should use it. In this case, we return
Ability.QUALITY_MALICIOUS, which tells the system that the skill is
always malicious to others, and that it will most likely anger the
target. It tells mobs to target this skill at enemies in combat</p>
      <p>Other possible values
include:</p>
      <a name="skillquality" id="skillquality"> </a>
      <table border="1">
        <tbody>
          <tr>
            <td>Ability.QUALITY_BENEFICIAL_SELF</td>
            <td>always helpful to
oneself when used</td>
          </tr>
          <tr>
            <td>Ability.QUALITY_BENEFICIAL_OTHERS</td>
            <td>can be targeted to
other people, and is always
beneficial</td>
          </tr>
          <tr>
            <td>Ability.QUALITY_OK_SELF</td>
            <td>targets oneself,
but is only useful in certain
circumstances, or it has complicated parameters that mobs won't find
useful</td>
          </tr>
          <tr>
            <td>Ability.QUALITY_OK_OTHERS</td>
            <td>targets other
people, but is only useful under certain
circumstances, or it also has complicated parameters</td>
          </tr>
          <tr>
            <td>Ability.QUALITY_INDIFFERENT</td>
            <td>targets items, or
rooms, and is only useful in certain
circumstances</td>
          </tr>
        </tbody>
      </table>
      <p>Only skills marked as
Ability.QUALITY_BENEFICIAL_*
or Ability.QUALITY_MALICIOUS will be used in combat or by most
behaviors.</p>
      <pre>  public int castingQuality( MOB invoker, Physical target )<br />  {<br />    return super.castingQuality( invoker, target );<br />  }<br /></pre>
      <p>This second most
important method is similar to the <code>abstractQuality()</code>
method above, but it tells the system what the quality of the skills or
spell is if it is specifically used by the given invoker against the
given target at this given time. If your skill is only useful in water
or against elves, it might be good to check to see if the invoker is in
water or the target is an elf before returning a value. The same kinds
of values may be returned from this method as are returned by
abstractQuality, except for QUALITY_OK_OTHERS and
Ability.QUALITY_OK_SELF, which are meaningless in this context.</p>
      <pre>  public boolean isAutoInvoked()<br />  {<br />    return false;<br />  }<br /></pre>
      <p>All skills are either
autoInvoking, or they must be invoked by
a player or mob. The value returned by this method determines which
sort this ability is. If it is autoinvoking, it will not have an
invoke( method as described below, nor will it have trigger strings,
nor will it return anything other than "" from it's <code>displayText()</code>
method. An example of an autoInvoking ability would be Blind Fighting
or Two Weapon Fighting. In our case, however, Trip is not autoinvoking,
but requires a player to invoke it.</p>
      <pre>  private static final String[] triggerStrings = { "TRIP" };<br />  public String[] triggerStrings()<br />  {<br />    return triggerStrings;<br />  }<br /><br />  public double castingTime(MOB mob, List&lt;String&gt; cmds)<br />  {<br />    return 0.25;<br />  }<br /><br />  public double combatCastingTime(MOB mob, List&lt;String&gt; cmds)<br />  {<br />    return 1.0;<br />  }<br /></pre>
      <p>For skills which are not
autoinvoking, like this one, we must
define an array of strings which constitute the command words to use
this skill. Each entry in the array must be only one word. If more than
one skill is found with the same trigger words (such as the spells,
which all share the trigger word "CAST"), then the name of the specific
ability will be the required next parameter. Trip, however, has a
unique trigger word, which is defined by this method.</p>
      <p>Skills can also define
how many actions they take to execute
when the caster or user of the skill is in combat, or not in combat.
The next two methods define this. A value of 0 means that the skill or
spell is always instantaneous. A higher value means that the skill
requires a full action to perform. Typical players have 1 action per
tick (4 second period) to use.</p>
      <pre>  public int classificationCode()<br />  {<br />    return Ability.ACODE_SKILL;<br />  }<br /></pre>
      <p>This important method
defines which category an ability falls
into. Possible values include: SKILL, PRAYER, SONG, TRAP, SPELL,
THIEF_SKILL, LANGUAGE, CHANT, COMMON_SKILL, DISEASE, or POISON.</p>
      <pre>  public long flags()<br />  {<br />    return Ability.FLAG_MOVING;<br />  }<br /></pre>
      <p>This method returns a
value consisting of one or more flags,
separated by | symbols in the same way that canAffectCode does above.
Each flag has a specific meaning and imparts information to the engine
about the ability. Possible values, which may be used alone or together
in any combination, include:</p>
      <a name="skillflags" id="skillflags"> </a>
      <table border="1" cellpadding="1" cellspacing="1" width="75%">
        <tbody>
          <tr>
            <td>FLAG_BINDING</td>
            <td>Binds and or
limits movement and the use of hands.</td>
          </tr>
          <tr>
            <td>FLAG_MOVING</td>
            <td>Changes the
position of the target or affected one.</td>
          </tr>
          <tr>
            <td>FLAG_TRANSPORTING</td>
            <td>Changes the room
of the target, requires that the
performer of the skill be present.</td>
          </tr>
          <tr>
            <td>FLAG_WEATHERAFFECTING</td>
            <td>Changes the
weather.</td>
          </tr>
          <tr>
            <td>FLAG_SUMMONING</td>
            <td>Changes the room
of the target, where the performer of
the skill is not present. May also bring new creatures into existence.</td>
          </tr>
          <tr>
            <td>FLAG_CHARMING</td>
            <td>Charms the target.</td>
          </tr>
          <tr>
            <td>FLAG_TRACKING</td>
            <td>Results in the
target tracking something.</td>
          </tr>
          <tr>
            <td>FLAG_HEATING</td>
            <td>Makes the target
hot.</td>
          </tr>
          <tr>
            <td>FLAG_BURNING</td>
            <td>Makes the target
on fire.</td>
          </tr>
          <tr>
            <td>FLAG_HOLY</td>
            <td>Means that the
skill is GOOD aligned, unless
FLAG_UNHOLY is also set, in which case it makes the skill NEUTRAL.</td>
          </tr>
          <tr>
            <td>FLAG_UNHOLY</td>
            <td>Means that the
skill is EVIL aligned, unless
FLAG_UNHOLY is also set, in which case it makes the skill NEUTRAL.</td>
          </tr>
          <tr>
            <td>FLAG_PARALYZING</td>
            <td>Makes the target
or affected one unable to move their
muscles.</td>
          </tr>
        </tbody>
      </table>
      <pre>  public void affectPhyStats( Physical affected, PhyStats affectableStats )<br />  {<br />    super.affectPhyStats( affected, affectableStats );<br />    if( !doneTicking )<br />    {<br />      affectableStats.setDisposition( affectableStats.disposition() | PhyStats.IS_SITTING);<br />    }<br />  }<br /></pre>
      <p>This is an example of the <code>affectPhyStats()</code>
method described in the Core Topics. In the case of our Trip skill, it
forces the affected target into a sitting position.</p>
      <pre>  public boolean okMessage( Environmental myHost, CMMsg msg )<br />  {<br />    if( ( affected == null ) || ( !( affected instanceof MOB ) ) )<br />    {<br />      return true;<br />    }<br /><br />    MOB mob = (MOB)affected;<br />    if( doneTicking &amp;&amp; msg.amISource( mob ) )<br />    {<br />      unInvoke();<br />    }<br />    else <br />    if( msg.amISource( mob )<br />    &amp;&amp; ( msg.sourceMinor() == CMMsg.TYP_STAND ))<br />    {<br />      return false;<br />    }<br />    return true;<br />  }<br /></pre>
      <p>This is an example of the <code>okMessage()</code>
method
described in the Core Topics. In this case, it intercepts messages
where the affected mob is trying to stand and cancels the message,
without comment, by returning false.</p>
      <pre>  public void unInvoke()<br />  {<br />    if( ( affected == null ) || ( !( affected instanceof MOB ) ) )<br />    {<br />      return;<br />    }<br /><br />    MOB mob = (MOB)affected;<br />    if( canBeUninvoked() )<br />    {<br />      doneTicking = true;<br />    }<br /><br />    super.unInvoke();<br /><br />    if( !mob.amDead() )<br />    {<br />      if( mob.location() != null )<br />      {<br />        CMMsg msg = CMClass.getMsg( mob, null, CMMsg.MSG_NOISYMOVEMENT, "&lt;S-NAME&gt; regain(s) &lt;S-HIS-HER&gt; feet.");<br />        if( mob.location().okMessage( mob, msg ) )<br />        {<br />          mob.location().send( mob, msg );<br />          CMLib.commands().postStand( mob, true );<br />        }<br />      }<br />      else<br />      {<br />        mob.tell( "You regain your feet." );<br />      }<br />    }<br />  }<br /></pre>
      <p>All standard abilities
include an <code>unInvoke()</code>
method, which is called when the Effect caused by the ability is
dispelled, or the duration of the ability expires. The <code>super.unInvoke()</code>
method, which is located in StdAbility.java, actually does the work of
removing the Effect from the affected object (stored in the variable
affected), and then setting affected to null. In this particular <code>unInvoke()</code>
method, we also see the code trying to force the mob back to his feet.</p>
      <pre>  public boolean preInvoke( MOB mob, List&lt;String&gt; commands, Physical givenTarget, boolean auto,<br />                            int asLevel, int secondsElapsed, double actionsRemaining )<br />  {<br />    return true;<br />  }<br /></pre>
      <p>The <code>preInvoke()</code>
method is an optional method
that
normally just returns true. Unless you have reason to do so, you do not
need to override the standard preInvoke method in StdAbility.java. The
preInvoke method must return true before the <code>invoke()</code>
method (below) is executed. The difference between the two is that the
preInvoke method is called at the moment the skill command words are
entered, even if the skill is coded, via the <code>castingTime()</code>
or <code>combatCastingTime()</code>
methods, to invoke at some later time. If your skill does invoke at a
later time, it is generally useful to use the preInvoke method to scan
the commands Vector, which contains the command parameter strings minus
any trigger words, for errors. You may also give the user a message
that their skill will invoke later on. The preInvoke method will
continue to be called, at 1 second intervals, until the player is able
to invoke the command.</p>
      <pre>  public boolean invoke( MOB mob, List&lt;String&gt; commands, Physical givenTarget, boolean auto, int asLevel )<br />  {<br /></pre>
      <p>If an ability is not
autoinvoked, it will always have a
functional invoke method. This invoke method includes the following
parameters: the mob invoking the ability and a vector of command
parameter strings (which does not include any trigger words). The
givenTarget parameter, which is null on normal ability invocations,
will have the value of a target to the skill if one is available. Calls
to the invoke method where the givenTarget is not null are typically
from potions, wands, traps, or other automatic invocations. Which
brings us to the last parameter, auto. Auto is false on normal
invocations of the skill, and true whenever the skill should always
invoke no matter what. Setting auto to true not only changes the output
string for the skill, but overrides proficiency checks as well.</p>
      <pre>    MOB target = this.getTarget( mob, commands, givenTarget );<br />    if( target == null )<br />    {<br />      return false;<br />    }<br /></pre>
      <p>Our first step in Trip is
to get our target. There are several <code>getTarget()</code>
methods built into StdAbility for
determining a target object based on the command parameters passed in,
as well as the <code>abstractQuality()</code>
value for the ability.
The StdAbility method call to <code>getTarget()</code>
is smart enough to know that if a target name is not specified by
givenTarget, and also one is not specified in the commands Vector
passed in, that it should choose whoever the mob is fighting, since the
ability isAbility.QUALITY_MALICIOUS. Non-malicious skills would not
follow this reasoning, but would choose the caster himself as default.</p>
      <p>All of the several <code>getTarget()</code>
methods will
generate their own error messages to the user if a target is not
specified, or found, or cannot be determined. For this reason, we need
only to check to see if a target has been returned. If not, we can
return false from <code>invoke()</code>,
telling the system that the
ability failed to invoke.</p>
      <pre>    if( CMLib.flags().isSitting( target )<br />    || CMLib.flags().isSleeping( target ))<br />    {<br />      mob.tell( target, null, null, "&lt;S-NAME&gt; is already on the floor!" );<br />      return false;<br />    }<br /><br />    if( !CMLib.flags().isAliveAwakeMobile( mob, true )<br />    ||( CMLib.flags().isSitting( mob ) ))<br />    {<br />      mob.tell( "You need to stand up!" );<br />      return false;<br />    }<br /><br />    if( mob.isInCombat() &amp;&amp; ( mob.rangeToTarget() &gt; 0 ) )<br />    {<br />      mob.tell( "You are too far away to trip!" );<br />      return false;<br />    }<br /><br />    if( target.riding() != null )<br />    {<br />      mob.tell( "You can't trip someone " + target.riding().stateString( target ) + " " + target.riding().name() + "!");<br />      return false;<br />    }<br /><br />    if( CMLib.flags().isFlying( target ) )<br />    {<br />      mob.tell( target.name(mob) + " is flying and can't be tripped!" );<br />      return false;<br />    }<br /></pre>
      <p>Here are numerous checks
to see if the invoking mob is able to
trip, and the target is able to be tripped.</p>
      <pre>    if( !super.invoke( mob, commands, givenTarget, auto ) )<br />    {<br />      return false;<br />    }<br /></pre>
      <p>The <code>invoke()</code>
method back up in StdAbility is
called now. This method will check mana requirements, and subtract mana
if necessary. It should be called AFTER all other preliminary checks
have been made.</p>
      <pre>    int levelDiff = target.phyStats().level() - mob.phyStats().level();<br />    if( levelDiff &gt; 0 )<br />    {<br />      levelDiff = levelDiff * 5;<br />    }<br />    else<br />    {<br />      levelDiff = 0;<br />    }<br /><br />    Double temp = Integer.valueOf(target.charStats().getStat(CharStats.STAT_DEXTERITY)).doubleValue() - 9.0;<br /><br />    int adjustment = (-levelDiff) + (-( 35 + ( (int)Math.round( temp * 3.0 ) ) ) );<br /><br />    boolean success = proficiencyCheck( mob, adjustment, auto );<br /></pre>
      <p>The <code>proficiencyCheck()</code>
method called at the end
here will determine of the user of the skill has passed their
proficiency check. The first parameter of this method is the invoking
mob, followed by either a positive (or helpful) adjustment, or a
negative (not helpful) adjustment. The second parameter is the auto
flag mentioned above, to allow overrides of the normal proficiency. In
the case of Trip, we calculate an adjustment based both on level and
the dexterity of the target. We store whether or not the proficiency
check failed or passed into the variable success.</p>
      <pre>    success = success &amp;&amp; ( target.charStats().getBodyPart( Race.BODY_LEG ) &gt; 0 );<br /><br />    if( success )<br />    {<br />      CMMsg msg = CMClass.getMsg( mob, target, this,<br />                                  CMMsg.MSK_MALICIOUS_MOVE|CMMsg.TYP_JUSTICE|( auto ? CMMsg.MASK_ALWAYS : 0 ),<br />                                  auto ? "&lt;T-NAME&gt; trip(s)!" : "^F&lt;S-NAME&gt; trip(s) &lt;T-NAMESELF&gt;!^?"<br />      );<br /><br />      if( mob.location().okMessage( mob, msg ) )<br />      {<br />        mob.location().send( mob, msg );<br />        int durationTicks = ( msg.value() &gt; 0 ) ? 1 : 2;<br />        maliciousAffect( mob, target, asLevel, durationTicks, -1 );<br />        target.tell( "You hit the floor!" );<br />      }<br />    }<br />    else<br />    {<br />      return maliciousFizzle( mob, target, "&lt;S-NAME&gt; attempt(s) to trip &lt;T-NAMESELF&gt;, but fail(s).");<br />    }<br /><br />    return success;<br />  }<br />}<br /></pre>
      <p>The rest of the <code>invoke()</code>
method actually does
the work of sending the trip message and affecting the target if
necessary, or sending the "fizzle" message if the proficiency check
failed (success was false).</p>
      <p>Of special note are some
of the other StdAbility method calls
in this section of code. You'll notice that the message constructed (as
per the Core Topics discussion in a previous section) in this case uses
a TYP_JUSTICE message (meaning an attack on dignity), with the
malicious and movement flags set. If this message gets sent, a call to <code>maliciousAffect()</code>
is made. The first parameter is the invoker, and the second parameter
is the one its being invoked upon. The third parameter is the level of
the affect, or 0 for default values. The forth parameter is the
duration of the Effect in ticks, which you can see is dependent in this
case upon whether the message came back with a <code>value()
&gt; 0</code>
(meaning the saving throw was made). If the forth parameter is 0, then
the default duration formula will be used. All other positive values,
such as in this case, denote a number of ticks of duration. The last
parameter, normally -1, asks <code>maliciousAffect()</code>
to give the target one more saving throw, against any of the valid
saving throw type messages, such as TYP_FIRE, TYP_ACID, TYP_GAS, etc.
The value of -1 means not to make any further saving throw attempts
before affecting the target.</p>
      <p>If this skill had not
been malicious, we could have made a
call to the <code>beneficialAffect()</code>
method instead. That
method has the same parameters as <code>maliciousAffect()</code>,
though it lacks the final parameter for a further saving throw, since
beneficial affects require no saving throw.</p>
      <p>Now, if the success
variable had been false, then we made a
call to the <code>maliciousFizzle()</code>
method. In addition to a display in the room, this method will make
sure the target knows that the invoking mob was trying to do something
bad to him or her, so that the target will get angry and start
fighting. Had this not been a malicious ability, we would have made
calls instead to either the <code>beneficialWordsFizzle()</code>
method, or the <code>beneficialVisualFizzle()</code>
method, depending upon whether the skill is verbal or somantic based.
Most spells are verbal based, for instance, while most skills are
somantic.</p>
      <p>Finally, we return the
results of the success variable from
the <code>invoke()</code>
method, to let the system know whether or not the ability succeeded. If
it did, the target will now be affected by this ability, and will have
to stay on the ground for a few ticks while the source mob pounds on
him or her.</p>
      <img src="images/fireball.jpg" alt="Spells" />
      <h2><a name="SPC" id="SPC">Spells, Prayers, and Chants</a></h2>
      <p>Spells, Prayers, and
Chants are all special forms of
Abilities. For this reason, it is required that you go back and read
the previous section on Skill Abilities before proceeding. You will
also be required to poke through the Core Topics elsewhere in this
document as well.</p>
      <h3><a name="spells" id="spells">Spells</a></h3>
      <p>Spells will follow all
the rules mentioned above in the Skill
Abilities section, with a few differences:</p>
      <pre>public class Spell_ResistFire extends com.planet_ink.coffee_mud.Abilities.Spells.Spell<br />{<br />  public String ID()<br />  {<br />    return "Spell_ResistFire";<br />  }<br /><br />  public String name()<br />  {<br />    return "Resist Fire";<br />  }<br /><br />  public String displayText()<br />  {<br />    return "(Resist Fire)";<br />  }<br /><br />  public int abstractQuality()<br />  {<br />    return Ability.QUALITY_BENEFICIAL_OTHERS;<br />  }<br /><br />  protected int canAffectCode()<br />  {<br />    return CAN_MOBS;<br />  }<br /><br />  public int classificationCode()<br />  {<br />    return Ability.ACODE_SPELL|Ability.DOMAIN_ABJURATION;<br />  }<br /></pre>
      <p>The first difference you
will notice above is that spells
extend the base class Spell.java found in the Abilities/Spells
directory instead of StdAbility. Spell.java also extends StdAbility as
well. The second difference is in the <code>classificationCode()</code>
method. You will notice that the domain of the spell is also specified.
In addition to the normal classification code of Ability.ACODE_SPELL,
the domain may be added using the | symbol. Possible domains include:</p>
      <a name="spelldomain" id="spelldomain"> </a>
      <table border="1">
        <tbody>
          <tr>
            <td>DOMAIN_DIVINATION</td>
            <td>Spells that grant
knowledge.</td>
          </tr>
          <tr>
            <td>DOMAIN_ABJURATION</td>
            <td>Spells that
protect.</td>
          </tr>
          <tr>
            <td>DOMAIN_ILLUSION</td>
            <td>Spells that fool
the senses.</td>
          </tr>
          <tr>
            <td>DOMAIN_EVOCATION</td>
            <td>Spells that bring
forth the elements.</td>
          </tr>
          <tr>
            <td>DOMAIN_ALTERATION</td>
            <td>Spells that change
things.</td>
          </tr>
          <tr>
            <td>DOMAIN_TRANSMUTATION</td>
            <td>Spells that change
people.</td>
          </tr>
          <tr>
            <td>DOMAIN_ENCHANTMENT</td>
            <td>Spells that
enchant items or the mind.</td>
          </tr>
          <tr>
            <td>DOMAIN_CONJURATION</td>
            <td>Spells that
transport people or items.</td>
          </tr>
        </tbody>
      </table>
      <pre>  public boolean invoke( MOB mob,List&lt;String&gt; commands, Physical givenTarget, boolean auto, int asLevel)<br />  {<br />    MOB target = getTarget( mob, commands, givenTarget );<br />    if( target == null )<br />    {<br />      return false;<br />    }<br /><br />    if( !super.invoke( mob, commands, givenTarget, auto ) )<br />    {<br />      return false;<br />    }<br /><br />    boolean success = proficiencyCheck( mob, 0, auto );<br />    if( success )<br />    {<br />      CMMsg msg = CMClass.getMsg( mob, target, this, affectType( auto ), auto ?<br />                                  "&lt;T-NAME&gt; feel(s) cooly protected."<br />                                : "^S&lt;S-NAME&gt; invoke(s) a cool field of protection around &lt;T-NAMESELF&gt;.^?"<br />      );<br /><br />      if( mob.location().okMessage( mob, msg ) )<br />      {<br />        mob.location().send( mob, msg );<br />        beneficialAffect( mob, target, asLevel, 0 );<br />      }<br />    }<br />    else<br />    {<br />       beneficialWordsFizzle( mob, target, "&lt;S-NAME&gt; attempt(s) to invoke fire protection, but fail(s).");<br />    }<br /><br />    return success;<br />  }<br />}<br /></pre>
      <p>The <code>invoke()</code>
method above follows the one in
Skill_Abilities very closely. You will see that no adjustment is made
to the proficiency check, and that, since this is not
aAbility.QUALITY_MALICIOUS ability, calls are made to <code>beneficialAffect()</code>
and <code>beneficialWordsFizzle()</code>
instead of <code>maliciousAffect()</code>
and <code>maliciousFizzle()</code>.
The main difference to notice
here, however, is the line constructing the evoking message. You will
notice that where the message code should be specified, a method call
to <code>affectType()</code>,
which is a method located in Spell.java, is made. This call will
automaticallyy construct the proper message type for a spell, taking
into accountAbility.QUALITY_MALICIOUSness, and whether the auto flag is
set. You will also notice that different message strings are
constructed depending upon whether the auto flag is set.</p>
      <h3><a name="prayers" id="prayers">Prayers</a></h3>
      <p>Prayers will follow all
the rules mentioned above in the Skill
Abilities section, with a few differences:</p>
      <pre>public class Prayer_Anger extends com.planet_ink.coffee_mud.Abilities.Prayers.Prayer<br />{<br />  public String ID()<br />  {<br />    return "Prayer_Anger";<br />  }<br /><br />  public String name()<br />  {<br />    return "Anger";<br />  }<br /><br />  public int abstractQuality()<br />  {<br />    return Ability.QUALITY_MALICIOUS;<br />  }<br /><br />  public long flags()<br />  {<br />    return Ability.FLAG_UNHOLY;<br />  }<br /><br />  public boolean invoke( MOB mob, List&lt;String&gt; commands, Physical givenTarget, boolean auto, int asLevel )<br />  {<br />    if( !super.invoke( mob, commands, givenTarget, auto ) )<br />    {<br />      return false;<br />    }<br /><br />    boolean success = proficiencyCheck( mob, 0, auto );<br /><br />    boolean someoneIsFighting = false;<br />    for( int i = 0; i &lt; mob.location().numInhabitants(); i++ )<br />    {<br />      MOB inhab = mob.location().fetchInhabitant( i );<br />      if( ( inhab != null ) &amp;&amp; ( inhab.isInCombat() ) )<br />      {<br />        someoneIsFighting = true;<br />      }<br />    }<br /><br />    if( success<br />    &amp;&amp;( !someoneIsFighting )<br />    &amp;&amp;( mob.location().numInhabitants() &gt; 3 ))<br />    {<br />      // it worked, so build a copy of this ability,<br />      // and add it to the effects list of the<br />      // affected MOB. Then tell everyone else<br />      // what happened.<br />       CMMsg msg = CMClass.getMsg( mob, null, this, affectType(auto), auto?"A feeling of anger descends": "^S&lt;S-NAME&gt; rage(s) for anger.^?" );<br /><br />       if( mob.location().okMessage( mob, msg ) )<br />       {<br />         mob.location().send( mob, msg );<br /><br />         [.......]<br />}<br /></pre>
      <p>The first difference you
may notice between this and the Skill
Ability discussed in the previous section is that this skill extends
the Prayer.java class instead of StdAbility. Prayer.java will make sure
that the <code>classificationCode()</code>
method returns the proper
value.</p>
      <p>You should also take note
of the <code>flags()</code>
method.
All Prayers must return a value from <code>flags()</code>
where either the FLAG_UNHOLY is set (meaning the Prayer is EVIL
aligned), FLAG_HOLY is set (meaning the Prayer is GOOD aligned), or
BOTH are set, in which case the Prayer is NEUTRAL.</p>
      <p>The last special note is
down in the message construction in
the <code>invoke()</code>
method. The <code>invoke()</code>
method above follows the one in Skill_Abilities very closely. You will
see that no adjustment is made to the proficiency check, for instance.
The main difference to notice here, however, is the line constructing
the evoking message. You will notice that where the message code should
be specified, a method call to <code>affectType()</code>,
which is a method located in Prayer.java, is made. This call will
automaticallyy construct the proper message type for a prayer, taking
into accountAbility.QUALITY_MALICIOUSness, and whether the auto flag is
set. You will also notice that different message strings are
constructed depending upon whether the auto flag is set.</p>
      <h3><a name="chants" id="chants">Chants</a></h3>
      <p>Chants will follow all
the rules mentioned above in the Skill
Abilities section, with a few differences:</p>
      <pre>public class Chant_AlterTime extends com.planet_ink.coffee_mud.Abilities.Druid.Chant<br />{<br />  public String ID()<br />  {<br />    return "Chant_AlterTime";<br />  }<br /><br />  public String name()<br />  {<br />    return "Alter Time";<br />  }<br /><br />  public String displayText()<br />  {<br />    return "";<br />  }<br /><br />  public int overrideMana()<br />  {<br />    return 100;<br />  }<br /><br />  public int abstractQuality()<br />  {<br />    return Ability.QUALITY_INDIFFERENT;<br />  }<br /><br />  protected int canAffectCode()<br />  {<br />    return 0;<br />  }<br /><br />  protected int canTargetCode()<br />  {<br />    return 0;<br />  }<br /><br />  public boolean invoke( MOB mob, List&lt;String&gt; commands, Physical givenTarget, boolean auto, int asLevel )<br />  {<br />    if( !super.invoke( mob, commands, givenTarget, auto ) )<br />    {<br />      return false;<br />    }<br /><br />    boolean success = proficiencyCheck( mob, 0, auto );<br />    if( success )<br />    {<br />      // it worked, so build a copy of this ability,<br />      // and add it to the effects list of the<br />      // affected MOB. Then tell everyone else<br />      // what happened.<br />      CMMsg msg = CMClass.getMsg( mob, null, this, affectType( auto ), auto ? "" : "^S&lt;S-NAME&gt; chant(s), and reality seems to start blurring.^?" );<br /><br />      if( mob.location().okMessage( mob, msg ) )<br />      {<br />        mob.location().send( mob, msg );<br />        int x = CMath.s_int( text() );<br />        while( x == 0 )<br />        {<br />          x = CMLib.dice().roll( 1, 3, -2 );<br />        }<br /><br />        if( x &gt; 0 )<br />        {<br />          mob.location().showHappens( CMMsg.MSG_OK_VISUAL, "Time moves forwards!" );<br />        }<br />        else<br />        {<br />          mob.location().showHappens( CMMsg.MSG_OK_VISUAL, "Time moves backwards!" );<br />        }<br /><br />        if( CMLib.map().numAreas() &gt; 0 )<br />        {<br />          CMLib.map().getFirstArea().tickTock( x );<br />        }<br />      }<br />    }<br />    else<br />    {<br />      return beneficialWordsFizzle( mob, null, "&lt;S-NAME&gt; chant(s), but the magic fades" );<br />    }<br /><br />    // return whether it worked<br />    return success;<br />  }<br />}<br /></pre>
      <p>The first difference you
may notice between this and the Skill
Ability discussed in the previous section is that this skill extends
the Chant.java class instead of StdAbility. Chant.java will make sure
that the <code>classificationCode()</code>
method returns the proper
value.</p>
      <p>You should also take note
that the <code>overrideMana()</code>
method is actually returning a value here of 100. This method allows
your ability to always cost the same amount of mana, regardless of the
invokers level. This method may be used in any ability, not just
chants. Also, this is not a method that is normally found in chants.
This particular chant, being deemed to be especially powerful, happens
to return a value for it. Normally this method would not be found.</p>
      <p>The last special note is
down in the message construction in
the <code>invoke()</code>
method. The <code>invoke()</code>
method above follows the one in Skill_Abilities very closely. You will
see that no adjustment is made to the proficiency check, for instance.
The main difference to notice here, however, is the line constructing
the evoking message. You will notice that where the message code should
be specified, a method call to <code>affectType()</code>,
which is a method located in Chant.java, is made. This call will
automaticallyy construct the proper message type for a chant, taking
into accountAbility.QUALITY_MALICIOUSness, and whether the auto flag is
set. You will also notice that different message strings are
constructed depending upon whether the auto flag is set.</p>
      <img src="images/elvis.jpg" alt="Songs" />
      <h2><a name="SONGS" id="SONGS">Songs</a></h2>
      <p>Although Songs also
follow the Skill Abilities rules above,
they are the most unique of skills. More than any other skill, they
rely very heavily on basic functionality provide by their appropriate
superclasses. For your sanity, I recommend that ALL of your coded songs
extend either com.planet_ink.coffee_mud.Abilities.Songs.Song,
com.planet_ink.coffee_mud.Abilities.Songs.Dance, or
com.planet_ink.coffee_mud.Abilities.Songs.Play. This is because those
classes provide very important basic functionality unique to songs, and
save you as the coder from having to worry about coding that unique
functionality yourself.</p>
      <p>By unique functionality,
I am referring to the way songs
behave when invoked in particular. They are always invoked upon groups,
and always require the invoker to remain in the room for the song to
remain in effect.</p>
      <pre>public class Song_Protection extends com.planet_ink.coffee_mud.Abilities.Songs.Song<br />{<br />  public String ID()<br />  {<br />    return "Song_Protection";<br />  }<br /><br />  public String name()<br />  {<br />    return "Protection";<br />  }<br /></pre>
      <p>Like the skill abilities
above, <code>ID()</code>
and <code>name()</code>
are implemented. The <code>name()</code>
will get intermingled into
the invocation text, so name your songs carefully, so they sound right
when invoked!</p>
      <pre>  public int abstractQuality()<br />  {<br />    return Ability.QUALITY_BENEFICIAL_OTHERS;<br />  }<br /> <br /></pre>
      <p>This method, discussed
above for skill abilities, is
absolutely vital for Songs, as it tells the Song superclass whether to
invoke the song upon all your enemies, or upon all your group members.
Make sure you implement this method!</p>
      <pre>  public void affectPhyStats( Physical affected, PhyStats affectableStats )<br />  {<br />    super.affectPhyStats( affected, affectableStats );<br />    if( invoker == null )<br />    {<br />      return;<br />    }<br /><br />    affectableStats.setAttackAdjustment( affectableStats.attackAdjustment() - 5 );<br />  }<br /> <br /></pre>
      <p>This particular song uses
affectPhyStats to lower the attack
rating of everyone that hears the song. Although this is not a
malicious song, it is the price of using it.</p>
      <pre>  public void affectCharStats( MOB affected, CharStats affectableStats )<br />  {<br />    super.affectCharStats( affected, affectableStats );<br />    if( invoker == null )<br />    {<br />      return;<br />    }<br /><br />    affectableStats.setStat( CharStats.STAT_DEXTERITY,<br />    affectableStats.getStat( CharStats.STAT_DEXTERITY ) - 1 );<br /><br />    affectableStats.setStat( CharStats.STAT_SAVE_ACID,<br />                             affectableStats.getStat( CharStats.STAT_SAVE_ACID )<br />                             + (invoker.charStats().getStat( CharStats.STAT_CHARISMA ) * 4)<br />                           );<br /><br />    affectableStats.setStat( CharStats.STAT_SAVE_COLD,<br />                             affectableStats.getStat( CharStats.STAT_SAVE_COLD )<br />                             + (invoker.charStats().getStat(CharStats.STAT_CHARISMA) * 4)<br />                           );<br /><br />    affectableStats.setStat( CharStats.STAT_SAVE_ELECTRIC,<br />                             affectableStats.getStat( CharStats.STAT_SAVE_ELECTRIC )<br />                             + ( invoker.charStats().getStat( CharStats.STAT_CHARISMA ) * 4 )<br />                           );<br /><br />    affectableStats.setStat( CharStats.STAT_SAVE_FIRE,<br />                             affectableStats.getStat( CharStats.STAT_SAVE_FIRE )<br />                             + ( invoker.charStats().getStat( CharStats.STAT_CHARISMA ) * 4 )<br />                           );<br /><br />    affectableStats.setStat( CharStats.STAT_SAVE_GAS,<br />                             affectableStats.getStat( CharStats.STAT_SAVE_GAS )<br />                             + ( invoker.charStats().getStat( CharStats.STAT_CHARISMA ) * 4 )<br />                           );<br />  }<br />}<br /></pre>
      <p>The most important thing
our sample song does is improve the
saving throws of everyone who hears it. The <code>affectCharStats()</code>
method makes that happen by modifying the appropriate saving throws in
affectableStats.</p>
      <img src="images/fun.jpg" alt="Common Skills" />
      <h2><a name="COMMON" id="COMMON">Common Skills</a></h2>
      <p>There are actually 3
unique kinds of common skills. One type
is simply a normal skill, just like the ones shown above. Another type
is the gathering skill, which is used to collect resources, and extends
com.planet_ink.coffee_mud.Abilities.Common.GatheringSkill. The last
type is the crafting skill, which extends
com.planet_ink.coffee_mud.Abilities.Common.CraftingSkill. In general,
common skills have this in common: they invoke immediately, but take a
long time to complete. They give messages of progress to the user, and
they immediately unInvoke themselves if the user leaves the room,
enters combat, or some other canceling condition arises.</p>
      <p><a name="skillgathering" id="skillgathering">Let's look
at a Gathering skill. Although Crafting skills are much more involved,
especially in the way they select the items they create, and in the way
they fill-in the variables for what they are creating, you will find
them remarkably similar to gathering skills.</a></p>
      <pre>public class Fishing extends com.planet_ink.coffee_mud.Abilities.Common.GatheringSkill<br />{<br />  public String ID()<br />  {<br />    return "Fishing";<br />  }<br /><br />  public String name()<br />  {<br />    return "Fishing";<br />  }<br /> <br /></pre>
      <p>If you've read the Skill
Abilities section above, you will
recognize these methods and their importance. As always, the <code>ID()</code>
must match the class name, while the <code>name()</code>
can be
whatever you want to call the skill.</p>
      <pre>  private static final String[] triggerStrings = { "FISH" };<br />  public String[] triggerStrings()<br />  {<br />    return triggerStrings;<br />  }<br /> <br /></pre>
      <p>And again, like a normal
skill, the common skills create and
return their invocation words (or "trigger strings" as they are called
in skills).</p>
      <pre>  public long flags()<br />  {<br />    return FLAG_GATHERING;<br />  }<br /><br />  public String supportedResourceString()<br />  {<br />    return "FLESH";<br />  }<br /> <br /></pre>
      <p>The <code>flags()</code>
method you will also recognize from
the Skill Abilities section. However, we've provided the system at
large with a flag to let it know that this skill is for gathering
resources, and not for crafting.</p>
      <p>The <code>supportedResourceString()</code>
is a great
supplementary method that is unique to Common Skills. It's purpose is
to inform the system what kinds of MATERIALS and RESOURCES are utilized
by this skill. Fishing is for catching fish, so we'll notify the system
that we deal in meat (flesh). Appropriate strings to return from this
method are listed in
com.planet_ink.coffee_mud.Items.interfaces.RawMaterial.java. If there
is more than one resource or material type, they are separated with the
pipe | character.</p>
      <pre>  protected Item found = null;<br />  protected String foundShortName = "";<br /> <br /></pre>
      <p>Almost all the common
skills create the item that they will
generate in the invoke method, store it in the skill, and then provide
it when the skill is unInvoked. For this reason, we'll need some
variables to store the object we will create, and a string for its name.</p>
      <pre>  public Fishing()<br />  {<br />    super();<br />    displayText = "You are fishing...";<br />    verb = "fishing";<br />  }<br /> <br /></pre>
      <p>Our constructor sets the
variable "verb", which is part of the
CommonSkill superclass. It is used when constructing sentences which
let the user and others around them know what they are doing.
displayText serves the same purpose described by the Skill Abilities
section above.</p>
      <pre>  public boolean tick( Tickable ticking, int tickID )<br />  {<br />    if( ( affected != null )<br />    &amp;&amp; ( affected instanceof MOB )<br />    &amp;&amp; ( tickID == Tickable.TICKID_MOB ))<br />    {<br />      MOB mob = (MOB)affected;<br />      if( tickUp == 6 )<br />      {<br />        if( found != null )<br />        {<br />          commonTell( mob, "You got a tug on the line!" );<br />        }<br />        else<br />        {<br />          StringBuffer str = new StringBuffer( "Nothing is biting around here.\n\r" );<br />          commonTell( mob, str.toString() );<br />          unInvoke();<br />        }<br />      }<br />    }<br />    return super.tick( ticking, tickID );<br />  }<br /> <br /></pre>
      <p>Although our common skill
super classes do most of the hard
work of maintaining the task being performed, you will still find that
they are often extended by individual common skills in other to give
more appropriate messages to the user. If you don't know what a tick
method is fore, read the Core Topic on the subject first. In this case,
before calling the superclasses tick method and letting it do most of
our work, we take a moment to check the tickUp integer maintained by
CommonSkill.java. That variable is incremented every 4 seconds after
the skill is invoked. in this case, after 24 seconds (6*4), we let the
user know whether or not an item was generated by the invoke method. If
an an item was invoked, we tell them they have hooked a fish. If an
item was not generated, we tell them that nothing is biting and
immediately <code>unInvoke()</code>
the skill.</p>
      <p>The <code>commonTell()</code>
method is another feature
unique
to common skills. Since common skills are often found on hireling mobs,
we wanted a special method which would tell players who invoke the
skill about the progress of our task, even if it is a follower that is
actually DOING the task. For instance, <code>commonTell()</code>
would tell a player who is fishing "You got a tug on the line!".
However, commonTell would force an NPC follower of a player to SAY "I
got a tug on the line!".</p>
      <pre>  public void unInvoke()<br />  {<br />    if( canBeUninvoked() )<br />    {<br />      if( ( affected != null ) &amp;&amp; ( affected instanceof MOB ) )<br />      {<br />        MOB mob = (MOB)affected;<br />        if( ( found != null )<br />        &amp;&amp; ( !aborted )<br />        &amp;&amp;( !helping ))<br />        {<br />          int amount = CMLib.dice().roll( 1, 5, 0 ) * ( abilityCode() );<br />          String s = "s";<br />          if( amount == 1 )<br />          {<br />            s = "";<br />          }<br /><br />          mob.location().show( mob, null, CMMsg.MSG_NOISYMOVEMENT, "&lt;S-NAME&gt; manage(s) to catch " + amount + " pound" <br />                               + s + " of " + foundShortName + "." );<br /><br />          for( int i = 0; i &lt; amount; i++ )<br />          {<br />            Item newFound = (Item)found.copyOf();<br />            mob.location().addItem( newFound, ItemPossessor.ItemExpiration.Player_Drop );<br /><br />            if( ( mob.riding() != null )<br />            &amp;&amp; ( mob.riding() instanceof Container ))<br />            {<br />              newFound.setContainer( (Container)mob.riding() );<br />            }<br />            CMLib.commands().postGet( mob, null, newFound, true );<br />          }<br />        }<br />      }<br />    }<br />    super.unInvoke();<br />  }<br /> <br /></pre>
      <p>As mentioned above, the <code>unInvoke()</code>
method is
where the final work is done. So long as the skill has not been aborted
(the aborted variable), or the skill was invoked only to help ANOTHER
player (the helping variable), we go ahead and create several copies of
our target item, put them in the room using addItem, and force
the player to get them into their inventory (if they can).</p>
      <pre>  public boolean invoke( MOB mob, List&lt;String&gt; commands, Physical givenTarget, boolean auto, int asLevel )<br />  {<br />    bundling = false;<br />    if( (!auto)<br />    &amp;&amp; ( commands.size() &gt; 0 )<br />    &amp;&amp; ( ( (String)commands.firstElement() ).equalsIgnoreCase( "bundle" ) ))<br />    {<br />      bundling = true;<br />      if( super.invoke( mob, commands, givenTarget, auto, asLevel ) )<br />      {<br />        return super.bundle( mob, commands );<br />      }<br />      return false;<br />    }<br /> <br /></pre>
      <p>The <code>invoke()</code>
method is where common skills do
99%
of their work, namely determining what the user wants to do and whether
they have the resources and are in the right place to do it, and then
actually generating the target item and filling it out. Then the invoke
method actually places the filled-out common skill on the player as an
"effect", allowing it to receive "tick" calls until it completes.</p>
      <p>In this case, right off
the bat we check to see if the user is
trying to use the Fishing skill to bundle up a pile of fish. If so, we
call a superclass helper method to do the bundling for us. The bundle
method which will happily use the <code>supportedResourceString()</code>
method above to determine what the player is allowed to bundle.</p>
      <pre>    int foundFish = -1;<br />    boolean maybeFish = false;<br />    if( mob.location() != null )<br />    {<br />      for( int i = 0; i &lt; RawMaterial.FISHES.length; i++ )<br />      {<br />        if( mob.location().myResource() == RawMaterial.FISHES[i] )<br />        {<br />          foundFish = RawMaterial.FISHES[i];<br />          maybeFish = true;<br />        }<br />        else <br />        if( ( mob.location().resourceChoices() != null )<br />        &amp;&amp; ( mob.location().resourceChoices().contains(Integer.valueOf( RawMaterial.FISHES[i] ) ) ) )<br />        {<br />          maybeFish = true;<br />        }<br />      }<br />    }<br /> <br /></pre>
      <p>Our next step is to
initialize a variable for the
com.planet_ink.coffee_mud.Items.interfaces.RawMaterial.java (resource)
code which will represent the type of fish we have caught here. We also
set a variable saying whether or not ANY fish are even POSSIBLY
available here.</p>
      <pre>    if( !maybeFish )<br />    {<br />      commonTell( mob, "The fishing doesn't look too good around here." );<br />      return false;<br />    }<br /> <br /></pre>
      <p>If maybeFish is false, we
are in a location where no fish are
even possibly available (such as a Desert room).</p>
      <pre>    verb = "fishing";<br />    found = null;<br />    playSound = "fishreel.wav";<br /> <br /></pre>
      <p>Otherwise, we
re-initialize the "verb" and "found" variables
we mentioned above, and set a CommonSkill string called "playSound"
which will be used to give our skill a little sound effect while it is
working.</p>
      <pre>    if( !super.invoke( mob, commands, givenTarget, auto, asLevel ) )<br />    {<br />      return false;<br />    }<br /> <br /></pre>
      <p>Next we call the
GatherSkill superclass invoke method. It is
important to note that several qualifying checks are made in that
method, such as whether the player is able to perform the skill. It
also subtracts the necessary mana or movement points for using the
skill.</p>
      <pre>    if( ( proficiencyCheck( mob, 0, auto ) )<br />    &amp;&amp; ( foundFish &gt; 0 ))<br />    {<br />      found = (Item)CMLib.materials().makeResource( foundFish, mob.location().domainType(), false, null );<br />      foundShortName = "nothing";<br />      if( found != null )<br />      {<br />        foundShortName = RawMaterial.CODES.NAME( found.material()).toLowerCase();<br />      }<br />    }<br /> <br /></pre>
      <p>Now we check to see if
two important conditions have occurred;
the first being whether the player has passed his or her proficiency
check, and the second being whether the foundFish variable was
assigned. Remember that the foundFish variable represents the material
&amp; resource code for the type of fish we will catch. If both of
those are true, we make use of a very useful method in the <code>utensils()</code>
library called makeResource to generate our item for us. We also
properly set the name of what we have caught based on the material type
of the foundFish.</p>
      <pre>    int duration = 35 - mob.phyStats().level();<br />    if( duration &lt; 10 )<br />    {<br />      duration=10;<br />    }<br /><br />    CMMsg msg = CMClass.getMsg( mob, found, this, CMMsg.MSG_NOISYMOVEMENT, "&lt;S-NAME&gt; start(s) fishing." );<br /><br />    if( mob.location().okMessage( mob, msg ) )<br />    {<br />      mob.location().send( mob, msg );<br />      found = (Item)msg.target();<br />      beneficialAffect( mob, mob, asLevel, duration );<br />    }<br />    return true;<br />  }<br />}<br /> <br /></pre>
      <p>Our last step is to
calculate the amount of time (duration)
that it will take to catch the fish, create a coffeemud message to
declare the start of our finishing adventure, and send the message out.
After doing so, notice that we re-set the found variable to <code>msg.target()</code>.
This may seem strange,
since, in the getMsg method, we already declared found to be our
message target. So isn't that like saying that A=A? Actually no!
Remember that the okMessage method may preview or *modify* a message.
Re-setting the found variable to <code>msg.target()</code>
is done to
support code which may have modified our target to something else.</p>
      <p><a name="skillcrafting" id="skillcrafting"> Now
we'll take
a look at a proper crafting skill. They are more complicated than
gathering skills, but you'll be able to apply almost all you learned by
reviewing the gathering skill to build a good picture of the way
crafting skills work. The first difference is that the crafting skills
extend com.planet_ink.coffee_mud.Abilities.Common.CraftingSkill. Many
of them also implement the
com.planet_ink.coffee_mud.Abilities.interfaces.ItemCrafter interface,
which allows them to provide items to other parts of coffeemud
instantly!</a></p>
      <pre>public class GlassBlowing extends CraftingSkill implements ItemCraftor<br />{<br />  public String ID()<br />  {<br />    return "GlassBlowing";<br />  }<br /><br />  public String name()<br />  {<br />    return "Glass Blowing";<br />  }<br /> <br /></pre>
      <p>If you've read the Skill
Abilities section above, you will
recognize these methods and their importance. As always, the <code>ID()</code>
must match the class name, while the <code>name()</code>
can be
whatever you want to call the skill.</p>
      <pre>  private static final String[] triggerStrings = { "GLASSBLOW", "GLASSBLOWING" };<br />  public String[] triggerStrings()<br />  {<br />    return triggerStrings;<br />  }<br /> <br /></pre>
      <p>And again, like a normal
skill, the common skills create and
return their invocation words (or "trigger strings" as they are called
in skills).</p>
      <pre>  public String supportedResourceString()<br />  {<br />    return "GLASS|SAND";<br />  }<br /> <br /></pre>
      <p>The <code>supportedResourceString()</code>
is a great
supplementary method that is unique to Common Skills. It's purpose is
to inform the system what kinds of MATERIALS and RESOURCES are utilized
by this skill. GlassBlowing is for turning sand into glass, so we'll
notify the system that we deal in sand and glass resources. Appropriate
strings to return from this method are listed in
com.planet_ink.coffee_mud.Items.interfaces.RawMaterial.java. If there
is more than one resource or material type, they are separated with the
pipe | character.</p>
      <pre>  protected static final int RCP_FINALNAME = 0;<br />  protected static final int RCP_LEVEL = 1;<br />  protected static final int RCP_TICKS = 2;<br />  protected static final int RCP_WOOD = 3;<br />  protected static final int RCP_VALUE = 4;<br />  protected static final int RCP_CLASSTYPE = 5;<br />  protected static final int RCP_MISCTYPE = 6;<br />  protected static final int RCP_CAPACITY = 7;<br />  protected static final int RCP_SPELL = 8;<br /> <br /></pre>
      <p>This list is at the core
of the crafting skills It represents
the name and function of each column of the crafting skill's text file.
Later on, we will use these constants to index into a Vector that
represents the particular row from the crafting skill's text file that
the player is building. </p>
      <pre>  public String parametersFormat()<br />  { <br />    return<br />    "ITEM_NAME\tITEM_LEVEL\tBUILD_TIME_TICKS\tMATERIALS_REQUIRED\tITEM_BASE_VALUE\t"<br />    +"ITEM_CLASS_ID\tLID_LOCK\tCONTAINER_CAPACITY||LIQUID_CAPACITY\tCODED_SPELL_LIST";<br />  }<br /> <br /></pre>
      <p>The&nbsp;<code>parametersFormat()</code>
method supports the
recipe
editors, both online and command line, but giving the engine a coded
representation of the meaning of each column as specified above.
&nbsp;Each column is tab-delimited, and each entry is one of the
specific value codes. &nbsp;If a column can have multiple meanings,
usually based on class, it is separated by <span
 style="font-family: monospace;">||</span>
characters. &nbsp; Value
codes include: &nbsp;<span style="font-family: monospace;">OPTIONAL_RESOURCE_OR_MATERIAL,
AMMO_TYPE, BASE_ARMOR_AMOUNT, WEAPON_TYPE, REQUIRED_COMMON_SKILL_ID,
AMMO_CAPACITY, MATERIALS_REQUIRED, SPELL_ID, CONTAINER_TYPE_OR_LIDLOCK,
ITEM_BASE_VALUE, ITEM_NAME, AMOUNT_MATERIAL_REQUIRED, N_A,
POSE_DESCRIPTION, RESOURCE_NAME, ATTACK_MODIFICATION, STATUE,
WEAPON_CLASS, LIQUID_CAPACITY, OPTIONAL_RACE_ID, RESOURCE_OR_MATERIAL,
CODED_WEAR_LOCATION, CONTAINER_TYPE, INSTRUMENT_TYPE,
CLAN_ITEM_CODENUMBER, MAXIMUM_RANGE, RESOURCE_OR_KEYWORD, LID_LOCK,
OPTIONAL_AMOUNT_REQUIRED, SMELL_LIST, LIGHT_DURATION, READABLE_TEXT,
CODED_SPELL_LIST, BUILD_TIME_TICKS, POSE_NAME, METAL_OR_WOOD,
RESOURCE_NAME_AMOUNT_MATERIAL_REQUIRED, CLAN_EXPERIENCE_COST_AMOUNT,
CLAN_AREA_FLAG, RESOURCE_NAME_OR_HERB_NAME, CONTAINER_CAPACITY,
ITEM_LEVEL, BASE_DAMAGE, ITEM_CLASS_ID, RIDE_CAPACITY, FOOD_DRINK,
WOOD_METAL_CLOTH, WEAPON_HANDS_REQUIRED, RIDE_BASIS, HERB_NAME,
SMOKE_FLAG, STONE_FLAG</span></p>
      <pre>  protected Item building = null;<br />  protected Item fire = null;<br />  protected boolean messedUp = false;<br /></pre>
      <p>As in the gathering
skill, we need to set up our global
variables to remember the object we are crafting, since it will be
constructed below in our invoke method, but not sent out into the world
until the unInvoke method. We also need a reference to the fire object
we are using, so we can watch and see if it goes out.</p>
      <pre>  public boolean tick( Tickable ticking, int tickID )<br />  {<br />    if( ( affected != null )<br />    &amp;&amp; ( affected instanceof MOB )<br />    &amp;&amp; ( tickID == Tickable.TICKID_MOB ))<br />    {<br />      MOB mob = (MOB)affected;<br />      if( ( building == null )<br />      || ( fire == null )<br />      || ( !CMLib.flags().isOnFire( fire ) )<br />      || ( !mob.location().isContent( fire ) )<br />      || ( mob.isMine( fire ) ) )<br />      {<br />        messedUp = true;<br />        unInvoke();<br />      }<br />    }<br />    return super.tick( ticking, tickID );<br />  }<br /> <br /></pre>
      <p>Unlike the gathering
skill, we will let the superclass tick
method do all the talking to the player. The only job being done here
is to make sure the fire didn't go out. If it did, we declare the
project messed up, and immediately unInvoke it.</p>
      <pre>  protected List&lt;List&lt;String&gt;&gt; loadRecipes()<br />  {<br />    return super.loadRecipes( "glassblowing.txt" );<br />  }<br /> <br /></pre>
      <p>Overriding the <code>loadRecipes()</code>
method is
absolutely
necessary for any crafting skill, as it specifies the recipes list. A
recipes list is a comma-delimited file where each row is linefeed
delimited. Each columns meaning is defined by the constants above. The
loadRecipes(String) method will automaticallyy look in
$coffeemud-install-path/resources/skills for the file specified.</p>
      <pre>  public void unInvoke()<br />  {<br />    if( canBeUninvoked() )<br />    {<br />      if( ( affected != null ) &amp;&amp; ( affected instanceof MOB ) )<br />      {<br />        MOB mob = (MOB)affected;<br /><br />        if( ( building != null ) &amp;&amp; ( !aborted ) )<br />        {<br />          if( messedUp )<br />          {<br />            commonTell( mob, CMStrings.capitalizeAndLower( building.name()) + " explodes!" );<br />          }<br />          else<br />          {<br />            mob.location().addItem( building, ItemPossessor.ItemExpiration.Player_Drop );<br />          }<br />        }<br />        building = null;<br />      }<br />    }<br />    super.unInvoke();<br />  }<br /> <br /></pre>
      <p>Just like in the
gathering skill, the <code>unInvoke()</code>
method is where we actually give our product to the world. Its been
saved in the 'building' variable reference, so its just a matter of
checking whether everything went ok and adding it to the room if things
did. Since common skills work by adding themselves as affects on the
player/mobs performing the skill, we need only check the
StdAbility.affected reference variable to find our craftor.</p>
      <pre><br />  @Override<br />  public boolean invoke(MOB mob, List&lt;String&gt; commands, Physical givenTarget, boolean auto, int asLevel)<br />  {<br />    // same invoke method as in all other Abilities, but we are redirecting to a special<br />    // method only for Crafting Skills.<br />    return autoGenInvoke(mob,commands,givenTarget,auto,asLevel,0,false,new Vector&lt;Item&gt;(0));<br />  }<br /><br />  @Override<br />  protected boolean autoGenInvoke(final MOB mob, List&lt;String&gt; commands, Physical givenTarget, final boolean auto, <br />                                  final int asLevel, int autoGenerate, boolean forceLevels, List&lt;Item&gt; crafted)<br /></pre>
      <p>Crafting skills are all
outfitted with the ability to allow
the rest of the system to use the skill class as an automatic item
generator. By convention, this is done by overriding the autoGenInvoke
interface, and then redirecting the normal invoke interface at it.
&nbsp;Then, by sending in the extra parameters, such as
autoGenerate,
which represents
the material out of which the item should be made, and maps back to one
of the RawMaterial.RESOURCE_* constants, it tells the rest of the code
to behave differently.</p>
      <pre>  randomRecipeFix( mob, addRecipes( mob, loadRecipes() ), commands, autoGenerate );<br /></pre>
      <p>This complex line does
the most important work related to the
autoGenerate flag we set above, and also to handle the case where mobs
are initiating this skill on their own. Embedded are three method
calls: one to get a vector of vectors representing the skill row matrix
(<code>loadRecipes()</code>),
another to append to this vector any
recipe Items in the mobs inventory (<code>addRecipes(..)</code>),
and
lastly, to randomly select a recipe based on the autoGenerate flag or
if the invoker is an NPC (<code>randomRecipeFix()</code>). <code>randomRecipeFix()</code>
can handle things like modifying the parameter list (commands) so that
it has the name of the random recipe selected.</p>
      <pre>  if( commands.size() == 0 )<br />  {<br />    commonTell( mob, "Make what? Enter \"glassblow list\" for a list." );<br />    return false;<br />  }<br /><br />  if( ( !auto )<br />  &amp;&amp; ( commands.size() &gt; 0 )<br />  &amp;&amp;( ( (String)commands.firstElement() ).equalsIgnoreCase( "bundle" ) ))<br />  {<br />    bundling = true;<br />    if( super.invoke( mob, commands, givenTarget, auto, asLevel ) )<br />    {<br />      return super.bundle( mob, commands );<br />    }<br />    return false;<br />  }<br /> <br /></pre>
      <p>Now we can finally start
dealing the the parameter list typed
by the player, or generated by the system. The parameter list (minus
the command invoking word) is in the "commands" vector as a set of
strings. The first thing we do is check the parameters to see if they
want to generate a bundle of raw resources. If they do, we call a
superclass helper method to do so and exit -- this is identical to the
way it was done in the gathering skill above.</p>
      <pre>  List&lt;List&lt;String&gt;&gt; recipes = addRecipes( mob, loadRecipes() );<br /> <br /></pre>
      <p>We're going to need that
final recipes list so we can search
for the one the player entered into the command line. Therefore we call
      <code>loadRecipes()</code>
to get the list from our text file, and then addRecipes to tack on any
Recipe Items in the mobs inventory. What comes back is our vector of
vectors, representing the rows and columns in the text file. Each
vector in the 'recipes' vector can be index by the RCP_* constants
above.</p>
      <pre>  String str = (String)commands.elementAt( 0 );<br />  String startStr = null;<br />  bundling = false;<br />  int completion = 4;<br /> <br /></pre>
      <p>Next we initialize a few
important variables, such as setting
a variable for the first word in the parameters (str), setting a
default completion ticks (4), and initializing a bundling flag to
false. Even if the player did not explicitly use the word bundle in the
parameters, they may still have selected a bundle item from the recipes
list, so we need that flag to notify the rest of the code of that fact.</p>
      <pre>  if( str.equalsIgnoreCase( "list" ) )<br />  {<br />    StringBuffer buf = new StringBuffer( CMStrings.padRight( "Item", 16 ) + " Lvl Sand required\n\r" );<br /><br />    for( int r = 0; r &lt; recipes.size(); r++ )<br />    {<br />      List&lt;String&gt; V = recipes.elementAt( r );<br />      if( V.size() &gt; 0 )<br />      {<br />        String item = replacePercent( V.elementAt( RCP_FINALNAME ), "" );<br />        int level = CMath.s_int( V.elementAt( RCP_LEVEL ) );<br />        int wood = CMath.s_int( V.elementAt( RCP_WOOD ) );<br />        if( level &lt;= mob.phyStats().level() )<br />        {<br />          buf.append( CMStrings.padRight( item, 16 ) + " " + CMStrings.padRight( "" + level, 3 ) + " " + wood + "\n\r" );<br />        }<br />      }<br />    }<br /><br />    commonTell( mob, buf.toString() );<br />    return true;<br />  }<br /> <br /></pre>
      <p>If the player entered
"list" as the first word in the
parameters, we display the recipes to them.</p>
      <pre>  fire = getRequiredFire( mob,autoGenerate );<br />  if( fire == null )<br />  {<br />    return false;<br />  }<br /><br />  building = null;<br />  messedUp = false;<br /></pre>
      <p>Now we know we are
definitely building something, so we can
initialize some more variables, such as the global messedUp flag and
the global building reference item. The global fire reference item is
also set here by calling a superclass helper method <code>getRequiredFire(..)</code>
which also has the
benefit of giving the user an error message if it fails to find a fire
to use. The autoGenerate flag is sent in to tell the method to skip the
check if we are simply using the invoke method to automaticallyy
generate an item.</p>
      <pre>  int amount = -1;<br />  if( ( commands.size() &gt; 1 )<br />  &amp;&amp; ( CMath.isNumber( (String)commands.lastElement() ) ))<br />  {<br />    amount = CMath.s_int( (String)commands.lastElement() );<br />    commands.removeElementAt( commands.size() - 1 );<br />  }<br /> <br /></pre>
      <p>Our next step is to check
the parameters list to see if the
player is specifying how much raw material they want to use in the
construction of this item. The recipe list mentions the minimum amount
of material, but the user is allowed to specify more if they like.
We'll save this override amount and confirm its validity later.</p>
      <pre>  String recipeName = CMParms.combine( commands, 0 );<br />  List&lt;String&gt; foundRecipe = null;<br />  List&lt;List&lt;String&gt;&gt; matches = matchingRecipeNames( recipes, recipeName, true );<br />  for( int r = 0; r &lt; matches.size(); r++ )<br />  {<br />    List&lt;String&gt; V = matches.get( r );<br />    if( V.size() &gt; 0 )<br />    {<br />      int level = CMath.s_int( (String)V.elementAt( RCP_LEVEL ) );<br />      if( ( autoGenerate &gt; 0 ) || ( level &lt;= mob.phyStats().level() ) )<br />      {<br />        foundRecipe = V;<br />        break;<br />      }<br />    }<br />  }<br /> <br /></pre>
      <p>Now we can actually get
to the important part of making sure
that the recipe name entered by the players into the command line is
actually a valid recipe. We do that by combining the remaining strings
on the command line into a single variable "recipeName", and then
calling a superclass helper method called "matchingRecipeNames" to
generate a subset of the master recipe list which matches that name.
Once we have this list of matching recipes, we can select the winner
based on level (unless we are performing an auto-generation, in which
case level doesn't matter). Our winning recipe is stored in a single
vector of strings called foundRecipe, which we can index by the RCP_*
constants.</p>
      <pre>  if( foundRecipe == null )<br />  {<br />    commonTell( mob, "You don't know how to make a '" + recipeName + "'. Try \"glassblow list\" for a list." );<br />    return false;<br />  }<br /> <br /></pre>
      <p>Of course, if no recipe
matched, or none met the level
requirements, our matched row vector will be null, in which case we
error out.</p>
      <pre>  int woodRequired = CMath.s_int( (String)foundRecipe.elementAt( RCP_WOOD ) );<br />  if( amount &gt; woodRequired )<br />  {<br />    woodRequired = amount;<br />  }<br /><br />  String misctype = (String)foundRecipe.elementAt( RCP_MISCTYPE );<br />  bundling = misctype.equalsIgnoreCase( "BUNDLE" );<br />  int[] pm = { RawMaterial.RESOURCE_SAND, RawMaterial.RESOURCE_CRYSTAL, RawMaterial.RESOURCE_GLASS };<br /><br />  int[][] data = fetchFoundResourceData( mob, woodRequired, "sand", pm, 0, null, null, bundling, autoGenerate );<br />  if( data == null )<br />  {<br />    return false;<br />  }<br /><br />  woodRequired = data[0][FOUND_AMT];<br /> <br /></pre>
      <p>However, if we did find a
matching row, its time to start
pulling information out of that row and start using it. The first thing
we check is the minimum required raw materials (woodRequired) which can
be modified by a larger "amount" variable by the player if they entered
one. We also draw out the general modifier string "misctype", which can
be used to specify parameters on the item being generated. For
instance, is the misctype column says "bundle", we know that we are
bundling raw resources and can set our bundling flag to true.</p>
      <p>The next step is a bit
more complicated. The pm array is
constructed of RawMaterial.RESOURCE_* constants which represent those
material or resource types valid for making the items in this common
skill. Next we call the powerful superclass method
fetchFoundResourceData which will return to us the amount and specific
type of valid resources found, and give an error if none are found. Of
course it doesn't really matter with the autoGenerate flag, so it will
take that into account as well. The returned array "data" has two
dimensions, 0 for the primary resource, and 1 for a secondary resource
if applicable (its not applicable here). Each dimension can be
dereferenced using superclass FOUND_* constants. For instance, we can
get a final "woodRequired" value from the data integer array.</p>
      <pre>  if( !super.invoke( mob, commands, givenTarget, auto, asLevel ) )<br />  {<br />    return false;<br />  }<br /> <br /></pre>
      <p>Just like for gathering
skills, the superclass invoke method
is called to take care of mana consumption, and to make sure the person
trying to do the crafting is not asleep or dead.</p>
      <pre>  int lostValue = destroyResources( mob.location(), woodRequired, data[0][FOUND_CODE], 0, null );<br /> <br />  if(autoGenerate&gt;0)<br />    lostValue = 0;<br />  building = CMClass.getItem( (String)foundRecipe.elementAt( RCP_CLASSTYPE ) );<br /><br />  if( building == null )<br />  {<br />    commonTell( mob, "There's no such thing as a " + foundRecipe.elementAt( RCP_CLASSTYPE ) + "!!!" );<br />   &nbsp;return false;<br />  }<br /> <br /></pre>
      <p>Our next step is to call
another superclass method <code>destroyResources()</code>
which will remove the resources from the room which are used to
construct the item. After that, we can actually initialize the building
item reference so we can begin to fill it out. The building variable
will remain referenced only by the common skill class until the <code>unInvoke()</code>
method is called, when it will be given to the craftor.</p>
      <pre>  completion = CMath.s_int( (String)foundRecipe.elementAt( RCP_TICKS ) ) <br />               - ( ( mob.phyStats().level() - CMath.s_int( (String)foundRecipe.elementAt( RCP_LEVEL ) ) ) * 2 );<br /><br />  String itemName = replacePercent(<br />  (String)foundRecipe.elementAt( RCP_FINALNAME ),<br />  RawMaterial.CODES.NAME( data[0][FOUND_CODE] ] ).toLowerCase();<br /><br />  if( bundling )<br />  {<br />    itemName = "a " + woodRequired + "# " + itemName;<br />  }<br />  else<br />  {<br />    itemName = CMStrings.startWithAorAn( itemName );<br />  }<br /><br />  building.setName( itemName );<br />  startStr = "&lt;S-NAME&gt; start(s) blowing " + building.name() + ".";<br />  displayText = "You are blowing " + building.name();<br />  verb = "blowing " + building.name();<br />  playSound = "fire.wav";<br />  building.setDisplayText( itemName + " is here" );<br />  building.setDescription( itemName + ". " );<br />  building.basePhyStats().setWeight( woodRequired );<br />  building.setBaseValue( CMath.s_int( (String)foundRecipe.elementAt( RCP_VALUE ) ) );<br /> <br /></pre>
      <p>Now that we have a
reference to the item object we are
building, we can start filling in some fields, such as its name,
display text, weight, and base value, usually from columns in our
recipe text file. We can also derive the final completion variable,
representing the number of ticks it will take to complete the item.</p>
      <pre>  if( data[0][FOUND_CODE] == RawMaterial.RESOURCE_SAND )<br />  {<br />    building.setMaterial( RawMaterial.RESOURCE_GLASS );<br />  }<br />  else<br />  {<br />    building.setMaterial( data[0][FOUND_CODE] );<br />  }<br /><br />  building.basePhyStats().setLevel( CMath.s_int( (String)foundRecipe.elementAt( RCP_LEVEL ) ) );<br /><br />  building.setSecretIdentity( "This is the work of " + mob.Name() + "." );<br />  int capacity = CMath.s_int( (String)foundRecipe.elementAt( RCP_CAPACITY ) );<br />  String spell = ( foundRecipe.size() &gt; RCP_SPELL ) ? ( (String)foundRecipe.elementAt( RCP_SPELL ) ).trim() : "";<br /><br />  addSpells( building, spell );<br /></pre>
      <p>Continuing with our
mission of filling out the building
object, we set the material type, level, and secret identity. We also
add any properties to it that are listed in the recipe text file by
calling the superclass helper method <code>addSpells()</code>.
There
is also a column in the recipe file for the capacity of the item if it
is a container.</p>
      <pre>  if( building instanceof Container )<br />  {<br />    if( capacity &gt; 0 )<br />    {<br />      ((Container)building ).setCapacity( capacity + woodRequired );<br />    }<br /><br />    if( misctype.equalsIgnoreCase( "LID" ) )<br />    {<br />      ((Container)building ).setDoorsNLocks( true, false, true, false, false, false );<br />    }<br />    else if( misctype.equalsIgnoreCase( "LOCK" ) )<br />    {<br />      ((Container)building ).setDoorsNLocks( true, false, true, false );<br />      ((Container)building ).setKeyName( Double.valueOf( Math.random() ).toString() );<br />    }<br />    ((Container)building ).setContainTypes( Container.CONTAIN_ANYTHING );<br />  }<br /> <br /></pre>
      <p>If, in fact, the item we
are building is a container, we'll
set the capacity of the container, and use our general purpose
"misctype" column from the table to determine whether a lit or lock
needs to be made.</p>
      <pre>  if( building instanceof Drink )<br />  {<br />    if( CMLib.flags().isGettable( building ) )<br />    {<br />      ((Drink)building ).setLiquidRemaining( 0 );<br />      ((Drink)building ).setLiquidHeld( capacity * 50 );<br />      ((Drink)building ).setThirstQuenched( 250 );<br /><br />      if( ( capacity * 50 ) &lt; 250 )<br />      {<br />        ((Drink)building ).setThirstQuenched( capacity * 50 );<br />      }<br />    }<br />  }<br /><br />  if( bundling )<br />  {<br />    building.setBaseValue( lostValue );<br />  }<br /> <br /></pre>
      <p>If the item is a
Drinkable, then we have a few more fields to
fill out, based on the capacity column. The last line makes sure that
the gold value of the item reflects the sum of the materials used, in
case we are bundling.</p>
      <pre>  building.recoverPhyStats();<br />  building.text();<br />  building.recoverPhyStats();<br /> <br /></pre>
      <p>The filling out of the
item is complete, so we call <code>recoverPhyStats()</code>,
populate the miscText field if the item is Generic, and then recover
the env stats again in case that changed anything.</p>
      <pre>  messedUp =! proficiencyCheck( mob, 0, auto );<br />  if( completion &lt; 4 )<br />  {<br />    completion = 4;<br />  }<br /><br />  if( bundling )<br />  {<br />    messedUp = false;<br />    completion = 1;<br />    verb = "bundling " + RawMaterial.CODES.NAME( building.material() ).toLowerCase();<br /><br />    startStr = "&lt;S-NAME&gt; start(s) " + verb + ".";<br />    displayText = "You are " + verb;<br />  }<br /> <br /></pre>
      <p>Now we can set our
messedUp flag based on a proficiency check,
and change our common skill player-message strings based on whether we
are bundling.</p>
      <pre>  if( autoGenerate &gt; 0 )<br />  {<br />    crafted.add( building );<br />    return true;<br />  }<br /> <br /></pre>
      <p>If the autoGenInvoke
method was called simply to generate the
item,
we are done -- we can add the item to the crafted list (where it
will be expected), and return.</p>
      <pre>  CMMsg msg = CMClass.getMsg( mob, building, this, CMMsg.MSG_NOISYMOVEMENT, startStr );<br /><br />  if( mob.location().okMessage( mob, msg ) )<br />  {<br />    mob.location().send( mob, msg );<br />    building = (Item)msg.target();<br />    beneficialAffect( mob, mob, asLevel, completion );<br />  }<br />  else if( bundling )<br />  {<br />    messedUp = false;<br />    aborted = false;<br />    unInvoke();<br />  }<br />  return true;<br />}<br />}<br /> <br /></pre>
      <p>Last but not least, we do
exactly what we did in our gathering
skill, namely generate a message for this event, and add the common
skill as an effect to the invoker of it. The completion time is used to
determine how long it will take to generate the item.</p>
      <img src="images/prayer.jpg" alt="poisons" />
      <h2><a name="POISON" id="POISON">Poisons</a></h2>
      <pre>public class Poison_BeeSting extends com.planet_ink.coffee_mud.Abilities.Poisons.Poison<br />{<br />  public String ID()<br />  {<br />    return "Poison_BeeSting";<br />  }<br /><br />  public String name()<br />  {<br />    return "Bee Sting";<br />  }<br /></pre>
      <p>The Poison base class in
the Poisons package provides a tidy
template upon which your more common, mundane poisons can be based. The
first three methods are those required by any Environmental class. The
fact that none of the other preliminary methods normally found in skill
abilities are present is a testimony to the homogeneous nature of
Poisons.</p>
      <pre>  private static final String[] triggerStrings = { "POISONSTING" };<br />  public String[] triggerStrings()<br />  {<br />    return triggerStrings;<br />  }<br /></pre>
      <p>Poisons have the feature
of having their own trigger commands,
meaning they can be added as attack abilities to monsters (like a Bee
in this case).</p>
      <pre>  protected String POISON_DONE()<br />  {<br />    return "The stinging poison runs its course.";<br />  }<br /><br />  protected String POISON_START()<br />  {<br />    return "^G&lt;S-NAME&gt; turn(s) green.^?";<br />  }<br /><br />  protected String POISON_CAST()<br />  {<br />    return "^F&lt;S-NAME&gt; sting(s) &lt;T-NAMESELF&gt;!^?";<br />  }<br /><br />  protected String POISON_FAIL()<br />  {<br />    return "&lt;S-NAME&gt; attempt(s) to sting &lt;T-NAMESELF&gt;, but fail(s).";<br />  }<br /></pre>
      <p>In this set of methods,
strings are defined for the invocation
of the poison, all the way through its recovery string.</p>
      <pre>  protected int POISON_TICKS()<br />  {<br />    return 10; // 0 means no adjustment!<br />  }<br /></pre>
      <p>Poisons can have a
variable duration dependent upon level (by
returning 0) or can have a set duration on the poisoned creature.</p>
      <pre>  protected int POISON_DELAY()<br />  {<br />    return 2;<br />  }<br /><br />  protected int POISON_DAMAGE()<br />  {<br />    return ( invoker != null ) ? 2 : 0;<br />  }<br /><br />  protected String POISON_AFFECT()<br />  {<br />    return "&lt;S-NAME&gt; cringe(s) from the poisonous itch.";<br />  }<br /></pre>
      <p>Poisons can also be set
to cause the poisoned creature to
emote on a regular basis, and to take damage as well. Here you can see
three methods being used to designate how often the emote/damage cycle
occurs (in ticks) as well as the amount of damage, and the text of the
emote.</p>
      <pre>  public void affectCharStats( MOB affected, CharStats affectableStats )<br />  {<br />    affectableStats.setStat( CharStats.STAT_CONSTITUTION, affectableStats.getStat( CharStats.STAT_CONSTITUTION ) - 1 );<br /><br />    affectableStats.setStat( CharStats.STAT_STRENGTH, affectableStats.getStat( CharStats.STAT_STRENGTH ) - 1 );<br /><br />    if( affectableStats.getStat( CharStats.STAT_CONSTITUTION ) &lt;= 0 )<br />    {<br />      affectableStats.setStat( CharStats.STAT_CONSTITUTION, 1 );<br />    }<br /><br />    if( affectableStats.getStat( CharStats.STAT_STRENGTH ) &lt;= 0 )<br />    {<br />      affectableStats.setStat( CharStats.STAT_STRENGTH, 1 );<br />    }<br />  }<br />}<br /></pre>
      <p>And lastly, as described
under the Core Topic on state
affects, we have the code which lowers the poisoned creatures
constitution and strength while the poison is in effect. We even have a
few lines to make sure the values don't fall below 0.</p>
      <img src="images/disease.jpg" alt="Diseases" />
      <h2><a name="DISEASE" id="DISEASE">Diseases</a></h2>
      <p>Like Poison, the Disease
base class in the Diseases package
provides a tidy template upon which your more common, mundane diseases
can be based.</p>
      <pre>public class Disease_Cold extends com.planet_ink.coffee_mud.Abilities.Diseases.Disease<br />{<br />  public String ID()<br />  {<br />    return "Disease_Cold";<br />  }<br /><br />  public String name()<br />  {<br />    return "Cold";<br />  }<br /><br />  public String displayText()<br />  {<br />    return "(Cold Virus)";<br />  }<br /><br />  protected int canAffectCode()<br />  {<br />    return CAN_MOBS;<br />  }<br /><br />  protected int canTargetCode()<br />  {<br />    return CAN_MOBS;<br />  }<br /><br />  public int abstractQuality()<br />  {<br />    return Ability.QUALITY_MALICIOUS;<br />  }<br /><br />  public boolean putInCommandlist()<br />  {<br />    return false;<br />  }<br /></pre>
      <p>The Disease base class
provides many important base services
that allows CoffeeMud to interact properly with your disease. For this
reason, making a disease that extends the Disease base class is highly
recommended. In the first half dozen methods, we see the important
values of a standard skill being defined. See the introduction to Skill
Abilities if you need more details on these methods.</p>
      <pre>  protected String DISEASE_DONE()<br />  {<br />    return "Your cold clears up.";<br />  }<br /><br />  protected String DISEASE_START()<br />  {<br />    return "^G&lt;S-NAME&gt; come(s) down with a cold.^?";<br />  }<br /></pre>
      <p>In this set of methods,
strings are defined for the invocation
of the disease as well as its recovery string.</p>
      <pre>  protected int DISEASE_TICKS()<br />  {<br />    return 24;<br />  }<br /></pre>
      <p>Diseases can have a
variable duration dependent upon level (by
returning 0) or can have a set duration on the diseased creature.</p>
      <pre>  protected int DISEASE_DELAY()<br />  {<br />    return 5;<br />  }<br /><br />  protected String DISEASE_AFFECT()<br />  {<br />    return "&lt;S-NAME&gt; sneeze(s). AAAAAAAAAAAAAACHOOO!!!!";<br />  }<br /></pre>
      <p>Diseases can also be set
to cause the poisoned creature to
emote on a regular basis. Here you can see a pair of methods being used
to designate how often the emote/damage cycle occurs (in ticks) as well
as the text of the emote. Any damage or other consequences of the
disease are defined later.</p>
      <pre>  public int spreadBitmap()<br />  {<br />    return DiseaseAffect.SPREAD_CONSUMPTION |DiseaseAffect.SPREAD_PROXIMITY |DiseaseAffect.SPREAD_CONTACT |DiseaseAffect.SPREAD_STD;<br />  }<br /></pre>
      <p>This important method is
used to define how the disease is
spread. Some aspects of disease catching must be coded by the
programmer of the disease. Some aspects are handled by the engine,
while most are handled by the Disease base class. This method is used
to coordinate the efforts on behalf of the disease by the CoffeeMud
engine as a whole. Different bit values are defined by the
DiseaseAffect interface.</p>
      <pre>  public boolean tick( Tickable ticking, int tickID )<br />  {<br />    if( !super.tick( ticking,tickID ) )<br />    {<br />      return false;<br />    }<br /><br />    if( affected == null )<br />    {<br />      return false;<br />    }<br /><br />    if( !( affected instanceof MOB ) )<br />    {<br />      return true;<br />    }<br /><br />    MOB mob = (MOB)affected;<br />    MOB diseaser = invoker;<br />    if( diseaser == null )<br />    {<br />      diseaser = mob;<br />    }<br /></pre>
      <p>If a disease does
anything during its delay cycle (defined
above by <code>DISEASE_DELAY()</code>),
then the programmer must implement a tick method to take care of this
functionality. These first few lines of the method are error and state
checking, as well as defining some useful variables, such as who caused
the disease (diseaser), and who has the disease (mob)</p>
      <pre>    if( ( getTickDownRemaining() == 1 )<br />    &amp;&amp;( CMLib.dice().rollPercentage() &gt; mob.charStats().getSave( CharStats.STAT_SAVE_COLD ) )<br />    &amp;&amp;( CMLib.dice().rollPercentage() &lt; 25 - mob.charStats().getStat( CharStats.STAT_CONSTITUTION ) )<br />    &amp;&amp;( !mob.amDead() )<br />    &amp;&amp;( !mob.isMonster() ))<br />    {<br />      mob.delEffect( this );<br />      Ability A = CMClass.getAbility( "Disease_Pneumonia" );<br />      A.invoke( diseaser, mob, true );<br />    }<br /></pre>
      <p>One of the things we have
decided to do in the disease Cold is
to make it so that, if the creature does not cure the disease before it
expires naturally, they will almost certainly catch Pneumonia. By
checking <code>getTickDownRemaining()</code>,
we check out counter
which runs downwards from <code>DISEASE_TICKS()</code>
to 0. At a
value of 1, we make a saving throw check for the creature with the
cold, and potentially give them another disease to enjoy when the Cold
expires 1 tick later.</p>
      <pre>    else if( ( !mob.amDead() ) &amp;&amp; ( ( --diseaseTick ) &lt;= 0 ) )<br />    {<br />      diseaseTick = DISEASE_DELAY();<br />      mob.location().show( mob, null, CMMsg.MSG_NOISE, DISEASE_AFFECT() );<br />      if( mob.curState().getHitPoints() &gt; ( ( 2 * diseaser.phyStats().level() ) + 1 ) )<br />      {<br />        int damage = CMLib.dice().roll( 2, diseaser.phyStats().level(), 1 );<br />        CMLib.combat().postDamage( diseaser, mob, this, damage, CMMsg.MASK_ALWAYS|CMMsg.TYP_DISEASE, -1, null );<br />      }<br /><br />      catchIt( mob );<br />      return true;<br />    }<br />    return true;<br />  }<br /></pre>
      <p>The last thing we do in
this method is, every <code>DISEASE_DELAY()</code>
ticks, we emote our DISEASE_AFFECT string, and then allow the creature
to take a few points of disease damage by calling the <code>MUDFight.postDamage()</code>
method. After this, we also call the <code>catchIt(MOB
mob)</code>
method up in the Disease base class. This important method spreads the
disease among those in the same room as the creature, thereby handling
any diseases spread by proximity as defined in <code>abilityCode()</code>
above.</p>
      <pre>  public void affectCharStats( MOB affected, CharStats affectableStats )<br />  {<br />    if( affected == null )<br />    {<br />      return;<br />    }<br /><br />    affectableStats.setStat( CharStats.STAT_CONSTITUTION, affectableStats.getStat( CharStats.STAT_CONSTITUTION ) - 2 );<br /><br />    affectableStats.setStat( CharStats.STAT_STRENGTH, affectableStats.getStat( CharStats.STAT_STRENGTH ) - 3 );<br /><br />    if( affectableStats.getStat( CharStats.STAT_CONSTITUTION ) &lt;= 0 )<br />    {<br />      affectableStats.setStat( CharStats.STAT_CONSTITUTION, 1 );<br />    }<br /><br />    if( affectableStats.getStat( CharStats.STAT_STRENGTH ) &lt;= 0 )<br />    {<br />      affectableStats.setStat( CharStats.STAT_STRENGTH, 1 );<br />    }<br />  }<br />}<br /></pre>
      <p>And lastly, as described
under the Core Topic on state
affects, we have the code which lowers the diseased creatures
constitution and strength while the disease is in effect. We even have
a few lines to make sure the values don't fall below 0.</p>
      <img src="images/traps.jpg" alt="Traps" />
      <h2><a name="TRAPS" id="TRAPS">Traps</a></h2>
      <p>Traps and Bombs are so
similar, that the differences are not
worth mentioning. However, although they are classified as skill
abilities, they are different from normal Skill Abilities mentioned
above in that they rely very heavily on their superclass bases, which
are com.planet_ink.coffee_mud.Abilities.Traps.StdTrap, and
com.planet_ink.coffee_mud.Abilities.Traps.StdBomb respectively. Making
a proper and compliant trap is helped considerably by following that
advice. Otherwise, so long as your trap implements the
com.planet_ink.coffee_mud.Abilities.interfaces.Trap interface, it will
be ok.</p>
      <pre>public class Trap_ElectricShock extends com.planet_ink.coffee_mud.Abilities.Traps.StdTrap<br />{<br />  public String ID()<br />  {<br />    return "Trap_ElectricShock";<br />  }<br /><br />  public String name()<br />  {<br />    return "electric shock";<br />  }<br /> <br /></pre>
      <p>If you've read the Skill
Abilities section above, you will
recognize these methods and their importance. As always, the <code>ID()</code>
must match the class name, while the <code>name()</code>
can be
whatever you want to call the skill.</p>
      <pre>  protected int canAffectCode()<br />  {<br />    return Ability.CAN_ITEMS|Ability.CAN_EXITS;<br />  }<br /><br />  protected int canTargetCode()<br />  {<br />    return 0;<br />  }<br /> <br /></pre>
      <p>It is very important,
even more so than normal skills, to make
sure that your StdAbility <code>canAffectCode()</code>
method returns a proper value. Some traps can be placed on rooms
(floors), and some on items, and others on exits. Make sure your method
informs StdAbility what your trap will do.</p>
      <pre>  protected int trapLevel()<br />  {<br />    return 19;<br />  }<br /> <br /></pre>
      <p>The <code>trapLevel()</code>
is the class level of your trap.
In general, a player needs this many levels in their trap-laying class
before they can create this trap.</p>
      <pre>  public String requiresToSet()<br />  {<br />    return "10 pounds of metal";<br />  }<br /> <br /></pre>
      <p>This is another
trap-specific method which is used by the Set
Traps skill to inform the user of what kinds of extra-materials are
required by the user before they can lay this particular trap. It will
be enforced below in the canSetTrap and setTrap methods.</p>
      <pre>  public Trap setTrap( MOB mob, Physical E, int trapBonus, int qualifyingClassLevel, boolean permanent )<br />  {<br />    if( E == null )<br />    {<br />      return null;<br />    }<br /><br />    if( mob != null )<br />    {<br />      Item I = findMostOfMaterial( mob.location(), RawMaterial.MATERIAL_METAL );<br />      if( I != null )<br />      {<br />        super.destroyResources( mob.location(), I.material(), 10 );<br />      }<br />    }<br />    return super.setTrap( mob, E, trapBonus, qualifyingClassLevel, permanent );<br />  }<br /> <br /></pre>
      <p>This method is used to
actually set the trap, well before the
trap is sprung. Springing is handled by the StdTrap superclass system,
and is based on what is returned by the <code>canAffectCode()</code>
method. The setTrap method received the mob/player setting the trap,
the item onto which the trap is being set (E -- I know, very
descriptive; sue me), the trapBonus of the trap setter, if any, and at
what level they first qualified for this trap. In this particular
method, we use some helper methods from StdTrap to find all of the
metal in the room, and then use another StdTrap superclass method to
remove the found metal from the room. <code>findMostOfMaterial()</code>
will look for any raw material Metals in the room, and return an
example Item representing the specific type (bronze, iron, gold) of
metal that is most numerous in the room. The <code>destroyResources()</code>
method then will remove 10 of those from the room.</p>
      <pre>  public boolean canSetTrapOn( MOB mob, Physical E )<br />  {<br />    if( !super.canSetTrapOn( mob, E ) )<br />    {<br />      return false;<br />    }<br /><br />    if( mob != null )<br />    {<br />      Item I = findMostOfMaterial( mob.location(), RawMaterial.MATERIAL_METAL );<br />      if( ( I == null )<br />      || ( super.findNumberOfResource( mob.location(), I.material() ) &lt; 10 ))<br />      {<br />        mob.tell( "You'll need to set down at least 10 pounds of metal first." );<br />        return false;<br />      }<br />    }<br />    return true;<br />  }<br /> <br /></pre>
      <p>This method is called
before the <code>setTrap()</code>
method to determine whether the given player/mob is allowed or able to
set the trap on the given object (E). Just as we did in setTrap above,
we use <code>findMostOfMaterial()</code>
to determine what the most
numerous metal resource on the room is, then call another StdTrap
superclass method, <code>findNumberOfResource()</code>,
to make sure there is enough of this particular metal resource to do
the job. If not, we inform the user and return false from the method.
If everything is fine, we return true. Notice that we were careful to
call the superclass version of this method -- it does important things
for us also, so it should definitely be called! </p>
      <pre>  public List&lt;Item&gt; getTrapComponents() <br />  {<br />    Vector V = new Vector();<br />    for( int i = 0 ; i &lt; 10 ; i++ )<br />       V.addElement( CMLib.materials().makeItemResource( RawMaterial.RESOURCE_IRON ) );<br />    return V;<br />  }<br /><br /> <br /></pre>
This
method is not a terribly important one, but helps serve skills that
allow traps to be disassembled. &nbsp;It fills a Vector with
something
that at least resembles as closely as possible the items that were
required to create the trap. &nbsp;In this case, we are calling the
makeItemResource method on the materials library to construct 10 pieces
of raw iron, which at least resembles our 10 pounds of metal
requirement.<br />
      <pre>  public void spring( MOB target )<br />  {<br />    if( ( target != invoker() ) &amp;&amp; ( target.location() != null ) )<br />    {<br />      if( ( !invoker().mayIFight( target ) )<br />      || ( CMLib.dice().rollPercentage() &lt;= target.charStats().getSave( CharStats.STAT_SAVE_TRAPS) ))<br />      {<br />        target.location().show( target, null, null, CMMsg.MASK_ALWAYS|CMMsg.MSG_NOISE, "&lt;S-NAME&gt; avoid(s) setting off a shocking trap!" );<br />      }<br />      else if( target.location().show( target, target, this, CMMsg.MASK_ALWAYS|CMMsg.MSG_NOISE, "&lt;S-NAME&gt; set(s) off an shocking trap!" ) )<br />      {<br />        super.spring( target );<br />        CMLib.combat().postDamage( invoker(), target, null, CMLib.dice().roll( trapLevel(), 8, 1 ), CMMsg.MASK_ALWAYS|CMMsg.TYP_ELECTRIC,<br />                                   Weapon.TYPE_STRIKING, "The shock &lt;DAMAGE&gt; &lt;T-NAME&gt;!" + CMLib.protocol().msp( "shock.wav",30 ) );<br /><br />        if( ( canBeUninvoked() ) &amp;&amp; ( affected instanceof Item ) )<br />        {<br />          disable();<br />        }<br />      }<br />    }<br />  }<br />}<br /></pre>
      <p>The spring method is
where the action is at. If the code in
StdTrap determines that the trap has been sprung, then this method will
be called with only one parameter, namely the mob who sprung it. After
making sure we aren't springing the trap on the thief who set it, we
make sure that the thief who set the trap is not breaking PK rules by
hurting the player. We do this using the <code>invoker()</code>
method
from StdAbility, which
will return a reference to the thief MOB who set the trap. We also give
the poor bloke who sprung the trap a saving throw. If both checks fail,
we let the room know that the trap has gone off. Notice that it is
inside this condition that we call <code>super.spring()</code>.
This is because, normally, the spring method is only supposed to hurt
people. Since we have lots of conditions by which the mob can get out
of being hurt, we need to wrap our call to <code>super.spring()</code>.
Anyway, since the trap has gone off, we make a library call to the <code>combat()</code>
engine's <code>postDamage()</code>
method. That method has lots of very complicated parameters, so you'll
have to read up on the Library section for more information on it, but
suffice to say that it posts the damage message that takes hit points
away from the player. Lastly, if the trap is allowed to be uninvoked,
we call the special StdTrap <code>disable()</code>
method, which makes
the trap unviable FOREVER. It effectively destroys the trap.</p>
      <img src="images/language.jpg" alt="Languages" />
      <h2><a name="LANGS" id="LANGS">Languages</a></h2>
      <p>Of all skills, you will
find that Languages are the easiest to
code. Although they fall into the category of Ability, and are a far
derivative of StdAbility, you will need very little of that extended
knowledge if you follow the K.I.S.S. principle and use the simple
template provided by the StdLanguage base class in the Languages
package, which implements the Language interface.</p>
      <pre>public class Elvish extends com.planet_ink.coffee_mud.Abilities.Languages.StdLanguage<br />{<br />  public String ID()<br />  {<br />    return "Elvish";<br />  }<br /><br />  public String name()<br />  {<br />    return "Elvish";<br />  }<br /></pre>
      <p>Like all Abilities, the
Language requires an ID which is the
same as its class name, and a readable name. In the case of Elvish,
they are identical.</p>
      <pre>  private static boolean mapped = false;<br />  public Elvish()<br />  {<br />    super();<br />    if( !mapped )<br />    {<br />      mapped = true;<br />      CMLib.ableMapper().addCharAbilityMapping( "All", 1, ID(), false );<br />    }<br />  }<br /></pre>
      <p>The constructor of this
language is worth noting. Under the
section on Character Classes, we learned how to make classes qualify
for skills. Languages, like Common Skills, are available to ALL
classes. For this reason, we save ourselves the trouble by having the
language declare its qualifications itself by accessing the same
CMLib.ableMapper()
method we saw up in Character Class creation.</p>
      <pre>  public static List&lt;String[]&gt; wordLists = null;<br />  public List&lt;String[]&gt; translationVector(String language)<br />  {<br />    if(wordLists==null)<br />    {<br />      String[] one = { "a", "e", "i", "o", "&iuml;&iquest;&frac12;", "&iuml;&iquest;&frac12;", "&iuml;&iquest;&frac12;", "&iuml;&iquest;&frac12;" };<br /><br />      String[] two = { "os", "vi", "ne", "vo", "li", "eh", "no", "ai", "by", "et", "ce", "un", "il" };<br /><br />      String[] three = { "&iuml;&iquest;&frac12;na", "cil", "sar", "tan", "hel", "loa", "sir", "hep", "yur", "nol", "hol", "qua", "&iuml;&iquest;&frac12;th" };<br /><br />      String[] four = { "s&iuml;&iquest;&frac12;ya", "qual", "quel", "lara", "uqua", "sana", "yava", "masse", "yanna", "quettaparma", "manna", "manan",<br />                        "merme", "carma", "harno", "harne", "varno", "essar", "saira", "cilta", "veuma", "norta", "turme", "saita" };<br /><br />      String[] five = { "cuiva", "cuina", "nonwa", "imire", "nauta", "cilta", "entuc", "norta", "latin", "l&iuml;&iquest;&frac12;tea", "veuya", "veuro",<br />                        "apama", "hampa", "nurta", "firta", "saira", "holle", "herwa", "uquen", "arcoa", "calte", "cemma", "hanta",<br />                        "tanen"};<br /><br />      String[] six = { "mahtale", "porisalque", "hairie", "tararan", "ambarwa", "latina", "ol&iuml;&iquest;&frac12;tie", "amawil", "apacen",<br />                       "yavinqua", "apalume", "linquilea", "menelwa", "alassea", "nurmea", "parmasse", "ceniril", "heldasse",<br />                       "imirin", "earina", "calatengew", "lapselunga", "rianna", "eneques" };<br /><br />      wordLists=new Vector();<br />      wordLists.add( one );<br />      wordLists.add( two );<br />      wordLists.add( three );<br />      wordLists.add( four );<br />      wordLists.add( five );<br />      wordLists.add( six );<br />    }<br />    return wordLists;<br />  }<br /></pre>
      <p>The first, often only,
and certainly most important Language
method is <code>translationVector(String
language)</code>,
which returns a Vector object containing a set of String arrays for the
given language id. The parameter is needed only if your language class
performs services for more than one spoken language, so usually the
parameter will be ignored. &nbsp;Each String array that is returned
by
this method is designated by the size of the Common language words
which will be used by the array for translation. That is to say,
whenever a Common word of three letters is being translated into
Elvish, the String array three will have a word randomly chosen from it.</p>
      <p>The words which are
placed into these string arrays is
arbitrary, and may actually contain as many or few letters as you like.
Keeping the number of letters close or the same as the Common word
equivalent provides a certain symmetry, however, and makes it fun for
the players who don't speak a language to try and guess what is being
said by counting letters.</p>
      <pre>  private static final Map&lt;String,String&gt; hashwords = new Hashtable();<br />  public Map&lt;String,String&gt; translationHash(String language)<br />  {<br />    if( ( hashwords != null ) &amp;&amp; ( hashwords.size() &gt; 0 ) )<br />    {<br />      return hashwords;<br />    }<br /><br />    hashwords.put( "ABANDON", "avarta" );<br />    hashwords.put( "ABLE", "pol" );<br />    hashwords.put( "ACCOMMODATE", "camta" );<br />    hashwords.put( "ACT", "car" );<br /><br /> ...<br /><br />    hashwords.put( "WRONG", "raic&iuml;&iquest;&frac12;" );<br />    hashwords.put( "YES", "y&iuml;&iquest;&frac12;" );<br />    hashwords.put( "YESTERDAY", "tellaur&iuml;&iquest;&frac12;" );<br />    return hashwords;<br />  }<br />}<br /></pre>
      <p>The last Language method
is <code>translationHash(String
language)</code>.
Like translationVector, it has a language parameter that can safely be
ignored. &nbsp;For that matter, this method is entirely optional
and
may be left out of a language definition. In fact, it usually IS left
out. However, when it is not, it provides a hashtable which can be used
to translate exact english matches back to the fantasy language. The
First word in each hashtable entry is the English word (and it MUST
MUST MUST be in UPPERCASE) as the key, and the translation word as the
entry value. Correct casing is taken care of by the Language base class.</p>
      </td>
    </tr>
  </tbody>
</table>
</center>
</body>
</html>
